From 5dacb60e098aeb182819968ded8e4516cd858e33 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 10 Jun 2015 04:17:31 +0200 Subject: [PATCH 001/103] FreeBSD fix for ethash byte ordering Changes from https://github.com/ethereum/cpp-ethereum/pull/1919 . It closes https://github.com/ethereum/cpp-ethereum/issues/1918 --- endian.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/endian.h b/endian.h index 0ee402d9a..6ca6cc036 100644 --- a/endian.h +++ b/endian.h @@ -32,6 +32,9 @@ #include #define ethash_swap_u32(input_) OSSwapInt32(input_) #define ethash_swap_u64(input_) OSSwapInt64(input_) +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) +#define ethash_swap_u32(input_) bswap32(input_) +#define ethash_swap_u64(input_) bswap64(input_) #else // posix #include #define ethash_swap_u32(input_) __bswap_32(input_) From 75e39b650d43fdc1e7fa70571e0976c4e21fcf25 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Jun 2015 10:05:33 +0200 Subject: [PATCH 002/103] fix expected section for ecrecover --- .../StateTestsFiller/stPreCompiledContractsFiller.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json b/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json index 8781e5271..1a951a432 100644 --- a/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json +++ b/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json @@ -140,7 +140,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0x3f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x" : "0x00", "0x01" : "0x00", "0x02" : "0x01" } @@ -226,7 +226,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0x3f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x" : "0x00", "0x01" : "0x00", "0x02" : "0x01" } @@ -1946,7 +1946,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0x3f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x" : "0x00", "0x01" : "0x00", "0x02" : "0x01" } @@ -2032,7 +2032,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0x3f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x" : "0x00", "0x01" : "0x00", "0x02" : "0x01" } @@ -3645,4 +3645,4 @@ "data" : "" } } -} \ No newline at end of file +} From ee06872b1927b6f88e2dc8892d94f00fecbe2a7e Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 12 Jun 2015 17:37:59 +0200 Subject: [PATCH 003/103] ImportRoute class instead of pair --- libethereum/BlockChain.cpp | 14 +++++++------- libethereum/BlockChain.h | 14 +++++++++++++- libethereum/Client.cpp | 13 +++++++------ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 480c7f977..b7618e2c7 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -326,8 +326,8 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st ImportRoute r; DEV_TIMED_ABOVE(Block import, 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); - fresh += r.first; - dead += r.second; + fresh += r.liveBlocks(); + dead += r.deadBlocks(); } catch (dev::eth::UnknownParent) { @@ -364,21 +364,21 @@ pair BlockChain::attemptImport(bytes const& _block, O } catch (UnknownParent&) { - return make_pair(ImportResult::UnknownParent, make_pair(h256s(), h256s())); + return make_pair(ImportResult::UnknownParent, ImportRoute()); } catch (AlreadyHaveBlock&) { - return make_pair(ImportResult::AlreadyKnown, make_pair(h256s(), h256s())); + return make_pair(ImportResult::AlreadyKnown, ImportRoute()); } catch (FutureTime&) { - return make_pair(ImportResult::FutureTime, make_pair(h256s(), h256s())); + return make_pair(ImportResult::FutureTime, ImportRoute()); } catch (Exception& ex) { if (m_onBad) m_onBad(ex); - return make_pair(ImportResult::Malformed, make_pair(h256s(), h256s())); + return make_pair(ImportResult::Malformed, ImportRoute()); } } @@ -699,7 +699,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& dead.push_back(h); else fresh.push_back(h); - return make_pair(fresh, dead); + return ImportRoute(dead, fresh); } void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 5f197cfee..6decf46b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -80,7 +80,19 @@ ldb::Slice toSlice(h256 const& _h, unsigned _sub = 0); using BlocksHash = std::unordered_map; using TransactionHashes = h256s; using UncleHashes = h256s; -using ImportRoute = std::pair; + +class ImportRoute +{ +public: + ImportRoute() {}; + ImportRoute(h256s const& _deadBlocks, h256s const& _liveBlocks): m_deadBlocks(_deadBlocks), m_liveBlocks(_liveBlocks) {}; + h256s const& deadBlocks() const { return m_deadBlocks; } + h256s const& liveBlocks() const { return m_liveBlocks; } + +private: + h256s m_deadBlocks; + h256s m_liveBlocks; +}; enum { ExtraDetails = 0, diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 5581d1071..9d2c9a9e6 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -613,10 +613,11 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) void Client::syncBlockQueue() { - ImportRoute ir; cwork << "BQ ==> CHAIN ==> STATE"; - tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 10 + 5); - if (ir.first.empty()) + pair blocks; + tie(blocks.first, blocks.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 10 + 5); + ImportRoute ir(blocks.second, blocks.first); + if (ir.liveBlocks().empty()) return; onChainChanged(ir); } @@ -658,7 +659,7 @@ void Client::syncTransactionQueue() void Client::onChainChanged(ImportRoute const& _ir) { // insert transactions that we are declaring the dead part of the chain - for (auto const& h: _ir.second) + for (auto const& h: _ir.deadBlocks()) { clog(ClientNote) << "Dead block:" << h; for (auto const& t: m_bc.transactions(h)) @@ -669,7 +670,7 @@ void Client::onChainChanged(ImportRoute const& _ir) } // remove transactions from m_tq nicely rather than relying on out of date nonce later on. - for (auto const& h: _ir.first) + for (auto const& h: _ir.liveBlocks()) { clog(ClientChat) << "Live block:" << h; for (auto const& th: m_bc.transactionHashes(h)) @@ -683,7 +684,7 @@ void Client::onChainChanged(ImportRoute const& _ir) h->noteNewBlocks(); h256Hash changeds; - for (auto const& h: _ir.first) + for (auto const& h: _ir.liveBlocks()) appendFromNewBlock(h, changeds); // RESTART MINING From 4036bd2d4ea15e6b2a95f9dda90d928de2895265 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 12 Jun 2015 22:10:22 +0200 Subject: [PATCH 004/103] add blck504980 test --- .../StateTestsFiller/stSpecialTestFiller.json | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/test/libethereum/StateTestsFiller/stSpecialTestFiller.json b/test/libethereum/StateTestsFiller/stSpecialTestFiller.json index 8dee4af11..60181bd5c 100644 --- a/test/libethereum/StateTestsFiller/stSpecialTestFiller.json +++ b/test/libethereum/StateTestsFiller/stSpecialTestFiller.json @@ -264,5 +264,229 @@ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000" } + }, + + "block504980" : { + "env" : { + "currentCoinbase" : "1cdc8315bdb1362de8b7b2fa9ee75dc873037179", + "currentDifficulty" : "21010229025", + "currentGasLimit" : "3141592", + "currentNumber" : "504780", + "currentTimestamp" : 1, + "previousHash" : "9ff4de714e01da9f8b61992efdab9b51ca14ac42d43f4c24df1d002a1239b1e9" + }, + "pre" : { + "b03f030056db7d467d778326658bac0d1b35d8f7" : { + "balance" : "0", + "code" : "0x600061075f537c010000000000000000000000000000000000000000000000000000000060003504731e147037f0a63df228fe6e7aef730f1ea31c8ce3602052730ea65418d7bf32680f55572c943a94b59080499860405273e509e3a93beb1eba72f8cb8d25f93a85e2d54afb60605273c9ae5868651bf7b7db6e360217db49ce4e69c07e60805273142a6927cf0060133187ba8a8e74d641438f0c1c60a05273b163e767e4c1ba5ae88b2ee7594f3a3fec2bb09660c05273ba7b277319128ef4c22635534d0f61dffdaa13ab60e052739761fecf88590592cf05ce545504d376d1693ab36101005273f70bbc50f1468cecae0761ef09386a87c1c696ea6101205273a89d22f049aaa5bbfb5f1a1939fff3ae7a26ae746101405273174827f7e53e8ce13b047adcac0eb3f2cb0c3285610160526336a560bd811415610a88576004356101a052601c60445990590160009052016327138bfb601c8203526101a051600482015260206101e0602483600060a051602d5a03f1506101e05190501515610195576001600003610200526020610200f35b601c6044599059016000905201637a66d7ca601c8203526101a051600482015260206102206024836000608051602d5a03f150610220519050601c606459905901600090520163cc1c944e601c8203526101a05160048201528160248201526020610260604483600061028051602d5a03f150610260519050601c60445990590160009052016380b5e7bd601c8203526101a051600482015260206102a06024836000606051602d5a03f1506102a0519050808202601c60445990590160009052016318633576601c8203526101a051600482015260206103006024836000608051602d5a03f150610300519050600981141561036d57601c60c459905901600090520163ac44d71e601c8203526101a0516004820152856024820152846044820152836064820152826084820152602061036060a483600061016051602d5a03f15061036051905050601c6064599059016000905201637265802d601c8203526101a05160048201526000602482015260206103806044836000608051602d5a03f15061038051905050601c604459905901600090520163c5476efe601c8203526101a051600482015260206103a06024836000608051602d5a03f1506103a051905050600185016103c05260206103c0f3610a3a565b60008114156103cd57601c60c459905901600090520163ef72638a601c8203526101a051600482015285602482015284604482015283606482015282608482015260206103e060a483600060c051602d5a03f1506103e051905050610a39565b600181141561042d57601c60c459905901600090520163a63e976c601c8203526101a0516004820152856024820152846044820152836064820152826084820152602061040060a483600060e051602d5a03f15061040051905050610a38565b600281141561048d57601c60c459905901600090520163533ea0ed601c8203526101a0516004820152856024820152846044820152836064820152826084820152602061042060a483600060e051602d5a03f15061042051905050610a37565b600381141561085057601c606459905901600090520163e05dcb56601c8203526101a0516004820152856024820152600285016040816020020159905901600090528160200260400181604485600061028051602d5a03f15060408101905090509050601c6044599059016000905201633d905045601c8203526101a051600482015260206104806024836000608051602d5a03f150610480519050600481141561063357601c60c4599059016000905201630939aa8c601c8203526101a051600482015287602482015286604482015285606482015284608482015260206104e060a483600061010051602d5a03f1506104e05190506104c052601c606459905901600090520163c286273a601c8203526101a05160048201526000602482015260206105006044836000608051602d5a03f1506105005190505060016104c05114156105e55782610520526020610520f361062e565b601c604459905901600090520163aac2ffb5601c8203526101a051600482015260206105406024836000608051602d5a03f1506105405190505060018301610560526020610560f35b610804565b600081141561069457601c60c459905901600090520163546fdeb3601c8203526101a0516004820152876024820152866044820152856064820152846084820152602061058060a483600061010051602d5a03f15061058051905050610803565b6001811415610742576000601c60c459905901600090520163de9080c8601c8203526101a051600482015288602482015287604482015286606482015285608482015260206105a060a483600061010051602d5a03f1506105a0519050141561073257601c6044599059016000905201631cda01ef601c8203526101a051600482015260206105c06024836000608051602d5a03f1506105c0519050505b826105e05260206105e0f3610802565b60028114156107a357601c60c459905901600090520163384ca8dd601c8203526101a0516004820152876024820152866044820152856064820152846084820152602061060060a483600061010051602d5a03f15061060051905050610801565b600381141561080057601c60c459905901600090520163d5dc5af1601c8203526101a0516004820152876024820152866044820152856064820152846084820152602061062060a483600061010051602d5a03f150610620519050505b5b5b5b5b601c6044599059016000905201631cda01ef601c8203526101a051600482015260206106406024836000608051602d5a03f1506106405190505082610660526020610660f35050610a36565b60048114156108b157601c60c459905901600090520163f6559853601c8203526101a0516004820152856024820152846044820152836064820152826084820152602061068060a483600061012051602d5a03f15061068051905050610a35565b600581141561091257601c60c459905901600090520163d8e5473d601c8203526101a051600482015285602482015284604482015283606482015282608482015260206106a060a483600061012051602d5a03f1506106a051905050610a34565b600681141561097357601c60c459905901600090520163090507ea601c8203526101a051600482015285602482015284604482015283606482015282608482015260206106c060a483600061012051602d5a03f1506106c051905050610a33565b60078114156109d457601c60c4599059016000905201635b911842601c8203526101a051600482015285602482015284604482015283606482015282608482015260206106e060a483600061014051602d5a03f1506106e051905050610a32565b6008811415610a3157601c60c459905901600090520163abe22b84601c8203526101a0516004820152856024820152846044820152836064820152826084820152602061070060a483600061014051602d5a03f150610700519050505b5b5b5b5b5b5b5b5b5b601c604459905901600090520163aac2ffb5601c8203526101a051600482015260206107206024836000608051602d5a03f1506107205190505060018101610740526020610740f350505050505b50", + "nonce" : "0", + "storage" : { + } + }, + "142a6927cf0060133187ba8a8e74d641438f0c1c" : { + "balance" : "0", + "code" : "0x600061031f537c01000000000000000000000000000000000000000000000000000000006000350473c9ae5868651bf7b7db6e360217db49ce4e69c07e602052730ea65418d7bf32680f55572c943a94b5908049986040526327138bfb81141561038d57600435608052601c6044599059016000905201637a66d7ca601c8203526080516004820152602060e06024836000602051602d5a03f15060e051905060a052601c604459905901600090520163c60409c6601c820352608051600482015260206101206024836000602051602d5a03f150610120519050430561010052600061014052600061016052600061018052600260a051016101005112151561010a576001610140525b60006101a052610100516101c0525b606461010051016101c051121561018457601c606459905901600090520163cc1c944e601c82035260805160048201526101c051602482015260206101e06044836000604051602d5a03f1506101e05190506101a051016101a05260016101c051016101c052610119565b6005601c606459905901600090520163cc1c944e601c820352608051600482015260a051602482015260206102006044836000604051602d5a03f1506102005190501280156101d357806101db565b600a6101a051125b9050156101eb57610140516101ee565b60005b1561033657601c604459905901600090520163c5476efe601c820352608051600482015260206102406024836000602051602d5a03f15061024051905050601c6064599059016000905201637265802d601c82035260805160048201526000602482015260206102606044836000602051602d5a03f15061026051905050601c606459905901600090520163c286273a601c82035260805160048201526000602482015260206102806044836000602051602d5a03f15061028051905050601c6044599059016000905201637a66d7ca601c820352608051600482015260206102a06024836000602051602d5a03f1506102a051905060a052601c608459905901600090520163bb8e4196601c820352608051600482015260a051602482015261010051604482015260206102c06064836000604051602d5a03f1506102c051905050610343565b6001610160526001610180525b61014051156103555761016051610358565b60005b156103665761018051610369565b60005b1561037f5760016102e05260206102e0f361038c565b6000610300526020610300f35b5b50", + "nonce" : "0", + "storage" : { + } + }, + "c9ae5868651bf7b7db6e360217db49ce4e69c07e" : { + "balance" : "0", + "code" : "0x600061083f537c010000000000000000000000000000000000000000000000000000000060003504637a66d7ca8114156100665760043560405260606060599059016000905260008152604051816020015260008160400152809050205460605260206060f35b63c60409c68114156100a55760043560405260606060599059016000905260008152604051816020015260018160400152809050205460a052602060a0f35b63186335768114156100e45760043560405260606060599059016000905260008152604051816020015260028160400152809050205460e052602060e0f35b63b3903c8a8114156101bc57600435604052606060605990590160009052600081526040518160200152600581604001528090502054610120526101205180602002602001599059016000905281815260208101905090506101605260006101c0525b610120516101c051121561019f57608060805990590160009052600081526040518160200152600481604001526101c051816060015280905020546101c05160200261016051015260016101c051016101c052610147565b6101605160206040820352602060208203510260400160408203f3505b636824e0fb8114156101fd57600435604052606060605990590160009052600081526040518160200152600581604001528090502054610220526020610220f35b633db16be381141561023e57600435604052606060605990590160009052600081526040518160200152600681604001528090502054610260526020610260f35b63c33878588114156102e05760006102a0526000546102c0526102c05180602002602001599059016000905281815260208101905090506102e0525b6102c0516102a05112156102c357604060405990590160009052600181526102a051816020015280905020546102a0516020026102e051015260016102a051016102a05261027a565b6102e05160206040820352602060208203510260400160408203f3505b63175c63228114156102fa57600054610380526020610380f35b63d861f2b4811415610336576004356103a052604060405990590160009052600181526103a051816020015280905020546103c05260206103c0f35b63b0dab01f81141561044f57600435610400526024356104205260443561044052606435610460526000606060605990590160009052600081526104005181602001526001816040015280905020541415610441576104205160606060599059016000905260008152610400518160200152600081604001528090502055610440516060606059905901600090526000815261040051816020015260018160400152809050205561046051606060605990590160009052600081526104005181602001526006816040015280905020556104005160406040599059016000905260018152600054816020015280905020556001600054016000556001610520526020610520f361044e565b6000610540526020610540f35b5b63aac2ffb58114156104b95760043560405260016060606059905901600090526000815260405181602001526002816040015280905020540160606060599059016000905260008152604051816020015260028160400152809050205560016105a05260206105a0f35b637265802d811415610507576004356040526024356105c0526105c0516060606059905901600090526000815260405181602001526002816040015280905020556001610600526020610600f35b63c5476efe811415610571576004356040526001606060605990590160009052600081526040518160200152600081604001528090502054016060606059905901600090526000815260405181602001526000816040015280905020556001610660526020610660f35b63c551e31e81141561063b576004356040526024356106805260606060599059016000905260008152604051816020015260058160400152809050205461012052610680516080608059905901600090526000815260405181602001526004816040015261012051816060015280905020556001606060605990590160009052600081526040518160200152600581604001528090502054016060606059905901600090526000815260405181602001526005816040015280905020556001610720526020610720f35b633d90504581141561067c57600435604052606060605990590160009052600081526040518160200152600381604001528090502054610740526020610740f35b631cda01ef8114156106e65760043560405260016060606059905901600090526000815260405181602001526003816040015280905020540160606060599059016000905260008152604051816020015260038160400152809050205560016107c05260206107c0f35b63c286273a811415610734576004356040526024356107e0526107e0516060606059905901600090526000815260405181602001526003816040015280905020556001610820526020610820f35b50", + "nonce" : "0", + "storage" : { + "0x72a539b064c98d29a514ee55694225e05fb41fe63e5fe710e4536bd9ba3591b4" : "0x338ecfe6c523ed1184918b19584d97dd1095ecaadc49c7ba9da62b8b513026e0", + "0xbc96058eb03504ee6f5c0a9582f8720d99a6e9738b171499507facff0b2c0b5b" : "0x9db6a4f2766b51013b8d2f9038131d1bb4af725d019d111d7e26ff96c023b23f", + "0x7aeb0a0ce8882a12d853078382a2bc72f7a94af6109f167de37b36c0a7deb828" : "0x4c428400ea8a7bd7c46ba9895b508770efa4551f0d793e1beb1207da01d9962f", + "0xde72f8eed43cc2a5a3eaa51483d14b17dc92bb26c154ae184cee4b4895011edc" : "0x47ce2b6fdb72c3fabb9c74f82c1e3e522bcd42e614fd85c208ac3c4c840cea72", + "0xcae57ae3017972d63effd8eae44f5054402c3e890d154b905ed6b5b533327fa9" : "0xd2e4bf465e61993d13089b940a7c55017a5117d8e43e4115550a139e1d4b3e3a", + "0x7c8f4a98e086f64e28c75f54712b5d44bec3c29b5c70519e8880d3046a5618dc" : "0xaafc1f2601752b114d722070f75539bfec7faf49f0d48a48d27862f0c3b09903", + "0xe0e687ddf317f3d2b209ae3884148eff0f636e16827f82eded14ada8fc603009" : "0xfa7c8939f9b033162cf8d75ea69671bb8a27041bd4cdc76594e61e99333cb041", + "0x687cb2122de7bacf42b9cd380b04ff2a2ce92a0b63706a9a78263b3ce86f3313" : "0x0000000000000000000000000000000000000000000000000200000000000000", + "0xe8cda339d72a1a350b62f1e3fa52e254c395cc9fdd9f60adb21c7633fbdab531" : "0x128c4fdf4801a30eae99dd58f0f3ff5ca65f71b66a9ac0f38dd450fb24b4aaaa", + "0xb1f1aaedfb83c7755a2bffc9e2557f1723f9abe5642397963e76248c9209af57" : "0xe9be955c5fbfcd846d7425eaea05ce897786aefad99665342cbf30761b352526", + "0x252a4ec7133643fddcdb22a86c415f78b2dd251f18d1efcd6a44acf590c4ae72" : "0x9caf94b82715869e71d3cee986094ea612f0258570b7e5ef47b5d09e9515322b", + "0x491d10658c1ec762152d8ad2d890ad59111b1ee7b4bc25736046923d3534d9a5" : "0x000000000000000000000000000000000000000000000000000000000000629e", + "0x5b0e8552efd72a845e47318abbbef9dc9fcdfe0d1a06cda44494401301581511" : "0xfbc98f4017ae5c20459daadaa6bee519b6de871d3dbaa9ab3f34340fef4cb643", + "0x618355e25491dfe86175f9d9b3147e4d680aa561d98384e3621dc6a3088b0846" : "0x6b2e6d2d5deb27dffec973f23af4caf111e66d1397f467dbbedf5ab2192fb6b6", + "0xb16b117660f31197087f4d6fe50d3d4579152244956f753f9653ccf85f4b35c4" : "0x830272e3bb35226b047244cbdc46f1b6b864a280461e7a592f70e0863f4f1d33", + "0x987cb9ecfd8ce499d9d0e9e6b7da29617aa02774a34f4a8ea54442f44a1e1936" : "0x5179f98f555f1e9f1d4a335d16f41154579a53e361e9859269b6fa74ea9c7d21", + "0x605b934bd26c9ecdf7029a7dc062d3a6b87338511cff96e0c5f13de9eea3462e" : "0xf0d24f3d0eda573fc5d43e3d0680993c51293752cd6de205040d3197f412f475", + "0x5b672a107ba6fab01cbddf079042e9f6176a8e6f154584fc4df4b15674c9456e" : "0x1603da41d610854d85536b37d000e5eb7ca09786c43f50e7441c0afbff1de0a9", + "0x0000000000000000000000000000000000000000000000000000000000000000" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0a4470e9d0419df71f6257fcdfd2c0a3bad96a23f5ab414bc10aaf1a31a536a7" : "0xb4876148229c22bd2291f1a4f5468c8c789b23639370c4d447f270ba341dbbec", + "0x84e4a80d33c5d2abd2b0a5aec0fdc5eaeed90ab31db556e404a81718ea286e39" : "0x000000000000000000000000000000000000000000000000000000000000001c", + "0x16ef4193a274568d283ff919c299729e07696d9ada48187b81d68e12e7b962de" : "0x0a103c04e7ecb9b3395f77c7b0cad28e62c85f042de4767ccc6c005e6f47f8d4", + "0xc186c4f377b7f13892ade9656acd1522aa1f8ac151ac4f62457b5073241d79fc" : "0x7289738fef00f1770eeb098db9bd486c01ac12398d79cdf935514a128c585c51", + "0xada5013122d395ba3c54772283fb069b10426056ef8ca54750cb9bb552a59e7d" : "0x00000000000000000000000000000000000000000000000000000000000f69b5", + "0xec5e7f54fa5e516e616b04f9d5a0ee433a80e09ed47d7e5269afd76c05ff251e" : "0x0000000000000000000000000000000000000000000000000000000000000014", + "0x1f1866e966f321b84535705846689749d34d5dc02994613e2931973c605d9e93" : "0xc723d0aa4a60529fe42277c8094aa19263aff36650136efc5edfd0785d457634", + "0x877305412fa2486f563c457b744e5c8b1e4d0eca73371de5e771f2abc263f4dc" : "0x7088a36f67276d475aa62127cfde9790cc802fdf3a54df49461a25eb8bf15707", + "0xcf569ee7bf3accc0f893dffd04f1a757f373efe80893eff504fb3678f688ec1d" : "0x0000000000000000000000000000000000000000000000000000000000000003", + "0x809c325f50acf5787776e960985e72443b4330ad1e2f466557fffee16ba51d44" : "0xb940a56e64b5b661d87919b8ef03640ec077a6d72dd0b524adedaa7ddc91ff7a", + "0xf9a3bf5f2ccb903ee1a7644113b794db0260de404fb8f11203e75a7fff151618" : "0xbd94773c0d85c68240ae8dfd53d9d33cd137509bfc5d3433381299df768c8377", + "0x922a8f2fc1cbe67c8acc6a8a720983c366d71d3e2e78e3048949ebc913ea611a" : "0x50fb9f913ca102534bb0a8eb8ebf19c68dfd16ffe5e207bcc580084cd4ecd8b4", + "0xb7bd50fdf7b043411c9ac33f0af2cebc69c393eb0b91f4976946f9c7b15ad0da" : "0xfccca0e7832bae9afe799a6d6177dc3869fa6c5b5105f8df6f365de5723820ec", + "0xd8f6f90f51e657690ee28d1cc80d81bc1b89290065891fdd853d09caaaf756aa" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x41b451e8d86d28add758cbd3f48a18fd04b11a80288c1dc434a5bf2d8fb1ca64" : "0xb602498f12a8b4af3a1fca357cea6b19bcd163dfec1d845364ce1395f7c21fa7", + "0x65112936bec0f1e84fda6623fb54e12baadc8a4a208c8c4eb3ed5e79cbd7e85f" : "0xa59ac24e3e0663413d0f87516ba8fb44c6c3e14da8eaabbde80f8ee285f65934", + "0xd69b7284545a9f5275df64ce94848dc954fcb8a8b525e7ac801517c12a75af84" : "0x4202995350abae303b43e564aa79121a30b5f1aea31f69cd25e07dd3fa64dce7" + } + }, + "0ea65418d7bf32680f55572c943a94b590804998" : { + "balance" : "0", + "code" : "0x600061289f537c01000000000000000000000000000000000000000000000000000000006000350473c9ae5868651bf7b7db6e360217db49ce4e69c07e60205263c4982a8581141561012757600435606052602435608052608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460a05260a051806020026020015990590160009052818152602081019050905060e0526000610140525b60a05161014051121561010b5760a060a0599059016000905260008152606051816020015260805181604001526001816060015261014051816080015280905020546101405160200260e051015260016101405101610140526100ad565b60e05160206040820352602060208203510260400160408203f3505b63cc1c944e8114156101765760043560605260243560805260806080599059016000905260008152606051816020015260805181604001526000816060015280905020546101a05260206101a0f35b6395a405b98114156101d5576004356060526024356080526044356101e05260a060a059905901600090526000815260605181602001526080518160400152600181606001526101e05181608001528090502054610200526020610200f35b6371ebb662811415610224576004356060526024356080526080608059905901600090526000815260605181602001526080518160400152600281606001528090502054610240526020610240f35b637a57a3db811415610325576004356060526024356080526044356102805260c060c0599059016000905260008152606051816020015260805181604001526003816060015261028051816080015260008160a0015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460200280806020015990590160009052818152602081019050905060005b602083048112156102e95780840154816020028301526001810190506102c8565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63f73dc690811415610394576004356060526024356080526044356103c0526064356103e05260c060c059905901600090526000815260605181602001526080518160400152600381606001526103c05181608001526103e0518160a001528090502054610400526020610400f35b6354cc61098114156103f3576004356060526024356080526044356103c05260a060a059905901600090526000815260605181602001526080518160400152600481606001526103c05181608001528090502054610440526020610440f35b63c63ef546811415610442576004356060526024356080526080608059905901600090526000815260605181602001526080518160400152600581606001528090502054610480526020610480f35b639381779b8114156105335760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600681606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260058160600152809050205460200280806020015990590160009052818152602081019050905060005b602083048112156104f75780840154816020028301526001810190506104d6565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b634f9c6eeb8114156106245760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600781606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260058160600152809050205460200280806020015990590160009052818152602081019050905060005b602083048112156105e85780840154816020028301526001810190506105c7565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b637dc121958114156107155760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600881606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260058160600152809050205460200280806020015990590160009052818152602081019050905060005b602083048112156106d95780840154816020028301526001810190506106b8565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63fa9832d18114156108065760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600981606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460200280806020015990590160009052818152602081019050905060005b602083048112156107ca5780840154816020028301526001810190506107a9565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b632c5a40d58114156108f75760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600a81606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260058160600152809050205460200280806020015990590160009052818152602081019050905060005b602083048112156108bb57808401548160200283015260018101905061089a565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63e05dcb568114156109eb5760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600b81606001526000816080015280905020600260806080599059016000905260008152606051816020015260805181604001526000816060015280905020546020020180806020015990590160009052818152602081019050905060005b602083048112156109af57808401548160200283015260018101905061098e565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63586b5be0811415610a3a576004356060526024356080526080608059905901600090526000815260605181602001526080518160400152600c81606001528090502054610b80526020610b80f35b63eb8af5aa811415610b585760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600d81606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460806080599059016000905260008152606051816020015260805181604001526005816060015280905020540560200280806020015990590160009052818152602081019050905060005b60208304811215610b1c578084015481602002830152600181019050610afb565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b637ab6ea8a811415610c765760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600e81606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460806080599059016000905260008152606051816020015260805181604001526005816060015280905020540560200280806020015990590160009052818152602081019050905060005b60208304811215610c3a578084015481602002830152600181019050610c19565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b632b810cb9811415610d945760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152600f81606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460806080599059016000905260008152606051816020015260805181604001526005816060015280905020540560200280806020015990590160009052818152602081019050905060005b60208304811215610d58578084015481602002830152600181019050610d37565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b637fb42e46811415610e855760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152601081606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460200280806020015990590160009052818152602081019050905060005b60208304811215610e49578084015481602002830152600181019050610e28565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63734fa727811415610f765760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152601181606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460200280806020015990590160009052818152602081019050905060005b60208304811215610f3a578084015481602002830152600181019050610f19565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63c67fa8578114156110675760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152601281606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460200280806020015990590160009052818152602081019050905060005b6020830481121561102b57808401548160200283015260018101905061100a565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b635ed853e48114156111855760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152601381606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460806080599059016000905260008152606051816020015260805181604001526005816060015280905020540560200280806020015990590160009052818152602081019050905060005b60208304811215611149578084015481602002830152600181019050611128565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63b86f51258114156112a35760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152601481606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460806080599059016000905260008152606051816020015260805181604001526005816060015280905020540560200280806020015990590160009052818152602081019050905060005b60208304811215611267578084015481602002830152600181019050611246565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63bc3d7d858114156113945760043560605260243560805260a060a059905901600090526000815260605181602001526080518160400152601581606001526000816080015280905020608060805990590160009052600081526060518160200152608051816040015260008160600152809050205460200280806020015990590160009052818152602081019050905060005b60208304811215611358578084015481602002830152600181019050611337565b602083066020036101000a60000381850154168160200283015281905090509050905060206040820352602060208203510260400160408203f3505b63a2302f2f81141561148157600435606052602435611680526044356116a0526116a05160a060a0599059016000905260008152606051816020015261168051816040015260018160600152608060805990590160009052600081526060518160200152611680518160400152600081606001528090502054816080015280905020556001608060805990590160009052600081526060518160200152611680518160400152600081606001528090502054016080608059905901600090526000815260605181602001526116805181604001526000816060015280905020556001611740526020611740f35b63058ca2bc8114156114dd576004356060526024356080526044356117605261176051608060805990590160009052600081526060518160200152608051816040015260028160600152809050205560016117a05260206117a0f35b635d3b965b8114156116175736599059016000905236600482376004356060526024356080526044356102805260643560208201016117e052608435611800525060c060c0599059016000905260008152606051816020015260805181604001526003816060015261028051816080015260008160a001528090502060206117e05103516020026020810460005b8181121561158c57806020026117e05101518482015560018101905061156b565b602083066020036101000a600003816020026117e05101511684820155505050506118005160806080599059016000905260008152606051816020015260805181604001526002816060015280905020540160806080599059016000905260008152606051816020015260805181604001526002816060015280905020556001611900526020611900f35b63b0e14f0f81141561167357600435606052602435608052604435611920526119205160806080599059016000905260008152606051816020015260805181604001526005816060015280905020556001611960526020611960f35b636acccdbc8114156117395736599059016000905236600482376004356060526024356080526044356020820101611980525060a060a05990590160009052600081526060518160200152608051816040015260068160600152600081608001528090502060206119805103516020026020810460005b8181121561170b5780602002611980510151848201556001810190506116ea565b602083066020036101000a600003816020026119805101511684820155505050506001611a40526020611a40f35b63a1fa51f98114156117ff5736599059016000905236600482376004356060526024356080526044356020820101611a60525060a060a0599059016000905260008152606051816020015260805181604001526007816060015260008160800152809050206020611a605103516020026020810460005b818112156117d15780602002611a60510151848201556001810190506117b0565b602083066020036101000a60000381602002611a605101511684820155505050506001611b20526020611b20f35b63cd87f43a8114156118c55736599059016000905236600482376004356060526024356080526044356020820101611b40525060a060a0599059016000905260008152606051816020015260805181604001526008816060015260008160800152809050206020611b405103516020026020810460005b818112156118975780602002611b4051015184820155600181019050611876565b602083066020036101000a60000381602002611b405101511684820155505050506001611c00526020611c00f35b63222a866381141561198b5736599059016000905236600482376004356060526024356080526044356020820101611c20525060a060a0599059016000905260008152606051816020015260805181604001526009816060015260008160800152809050206020611c205103516020026020810460005b8181121561195d5780602002611c205101518482015560018101905061193c565b602083066020036101000a60000381602002611c205101511684820155505050506001611ce0526020611ce0f35b63b39e1faa811415611a515736599059016000905236600482376004356060526024356080526044356020820101611d00525060a060a059905901600090526000815260605181602001526080518160400152600a816060015260008160800152809050206020611d005103516020026020810460005b81811215611a235780602002611d0051015184820155600181019050611a02565b602083066020036101000a60000381602002611d005101511684820155505050506001611dc0526020611dc0f35b63e365736b811415611b175736599059016000905236600482376004356060526024356080526044356020820101611de0525060a060a059905901600090526000815260605181602001526080518160400152600b816060015260008160800152809050206020611de05103516020026020810460005b81811215611ae95780602002611de051015184820155600181019050611ac8565b602083066020036101000a60000381602002611de05101511684820155505050506001611ea0526020611ea0f35b63aad7d6e3811415611b7357600435606052602435608052604435611ec052611ec0516080608059905901600090526000815260605181602001526080518160400152600c816060015280905020556001611f00526020611f00f35b6301112b27811415611c395736599059016000905236600482376004356060526024356080526044356020820101611f20525060a060a059905901600090526000815260605181602001526080518160400152600d816060015260008160800152809050206020611f205103516020026020810460005b81811215611c0b5780602002611f2051015184820155600181019050611bea565b602083066020036101000a60000381602002611f205101511684820155505050506001611fe0526020611fe0f35b63bdbb239b811415611cff5736599059016000905236600482376004356060526024356080526044356020820101612000525060a060a059905901600090526000815260605181602001526080518160400152600e8160600152600081608001528090502060206120005103516020026020810460005b81811215611cd1578060200261200051015184820155600181019050611cb0565b602083066020036101000a6000038160200261200051015116848201555050505060016120c05260206120c0f35b6305a0cd48811415611dc557365990590160009052366004823760043560605260243560805260443560208201016120e0525060a060a059905901600090526000815260605181602001526080518160400152600f8160600152600081608001528090502060206120e05103516020026020810460005b81811215611d9757806020026120e051015184820155600181019050611d76565b602083066020036101000a600003816020026120e051015116848201555050505060016121a05260206121a0f35b63aaa1fe35811415611e8b57365990590160009052366004823760043560605260243560805260443560208201016121c0525060a060a05990590160009052600081526060518160200152608051816040015260108160600152600081608001528090502060206121c05103516020026020810460005b81811215611e5d57806020026121c051015184820155600181019050611e3c565b602083066020036101000a600003816020026121c05101511684820155505050506001612280526020612280f35b632be4935d811415611f5157365990590160009052366004823760043560605260243560805260443560208201016122a0525060a060a05990590160009052600081526060518160200152608051816040015260118160600152600081608001528090502060206122a05103516020026020810460005b81811215611f2357806020026122a051015184820155600181019050611f02565b602083066020036101000a600003816020026122a05101511684820155505050506001612360526020612360f35b6313a8350d8114156120175736599059016000905236600482376004356060526024356080526044356020820101612380525060a060a05990590160009052600081526060518160200152608051816040015260128160600152600081608001528090502060206123805103516020026020810460005b81811215611fe9578060200261238051015184820155600181019050611fc8565b602083066020036101000a600003816020026123805101511684820155505050506001612440526020612440f35b63cb540b458114156120dd5736599059016000905236600482376004356060526024356080526044356020820101612460525060a060a05990590160009052600081526060518160200152608051816040015260138160600152600081608001528090502060206124605103516020026020810460005b818112156120af57806020026124605101518482015560018101905061208e565b602083066020036101000a600003816020026124605101511684820155505050506001612520526020612520f35b63be0306278114156121a35736599059016000905236600482376004356060526024356080526044356020820101612540525060a060a05990590160009052600081526060518160200152608051816040015260148160600152600081608001528090502060206125405103516020026020810460005b81811215612175578060200261254051015184820155600181019050612154565b602083066020036101000a600003816020026125405101511684820155505050506001612600526020612600f35b6383fd77f08114156122695736599059016000905236600482376004356060526024356080526044356020820101612620525060a060a05990590160009052600081526060518160200152608051816040015260158160600152600081608001528090502060206126205103516020026020810460005b8181121561223b57806020026126205101518482015560018101905061221a565b602083066020036101000a6000038160200261262051015116848201555050505060016126e05260206126e0f35b63594622058114156122d5576004356060526024356080526044356103c052606435612700526127005160a060a059905901600090526000815260605181602001526080518160400152600481606001526103c051816080015280905020556001612740526020612740f35b63bb8e419681141561244857600435606052602435612760526044356127805260006127a0525b6080608059905901600090526000815260605181602001526001612760510381604001526000816060015280905020546127a051121561243b5760a060a05990590160009052600081526060518160200152600161276051038160400152600181606001526127a0518160800152809050205460a060a05990590160009052600081526060518160200152612780518160400152600181606001526080608059905901600090526000815260605181602001526127805181604001526000816060015280905020548160800152809050205560016080608059905901600090526000815260605181602001526127805181604001526000816060015280905020540160806080599059016000905260008152606051816020015261278051816040015260008160600152809050205560016127a051016127a0526122fc565b6001612880526020612880f35b50", + "nonce" : "0", + "storage" : { + "0xc2a26b80067fc36b8268b0d5b31afff953fa91cebea39f191e2763d6e71259b9" : "0x02a43c547fe8de2400d2a141016550e8bae058d41164247c099e787ddd40e789", + "0x12643ff300762717d27efb567b82c65560d7b43249d908504e5510863ab82aac" : "0x154cf60e137c594516a065149610b6a3989396a42581d5fd8919e711c55da225", + "0xcbd6ae6bd61bc9270ec836f1919b3268113abe076c7febfdb8cf573b199ce9a9" : "0xf402b17773c1f7534034ee58dc0d2a3421470a7a67daf4fa790dc3b420eef790", + "0x417be8bc6791807372e0222a350bb8a5d67bbc8d7595c301d8a5a8372cfdcef1" : "0xabd4971b4605a7155802f70e08298b1ceb0e4e4eaccccd348f77a77227f73a7f", + "0x065d5efdfcc0fba693dc9e467f633097ffdc97401901463ad0e28855486d1edf" : "0xb9d69098a6acfe0c6411bcaaf430f78d363a9adc32b78bc2e15ccd6e883e9784", + "0x19efb13d6576359514ace5211988a8d51379fa88ccd2b886b409f842b13d7932" : "0x00c849cc595b452d11c206d2eb8cdfa06de211e3ff19ee0e0276dc857c05d4fe", + "0xaa0dbf8241ef3ae07c254e6869e84895ba2be0779a7f261c8308a3114be1c54a" : "0x0000000000000000000000000000000000000000000000000000000000000004", + "0xa0953566119395c11186b334805fc1a16175ecac0ecc93ae0322264f0dc2e40d" : "0x10c5a00466ab7c0adae1e93537cc275ea8cf23ff509d5466a1fd6f56b0a61d1b", + "0x9fddf1db29caa5c1239edd86e9e0835cdfe41f7253ec78f62d3da8558d6f3cd7" : "0x104eef8fa35bf39f677d81855bc0b9f42317f32792e98e95e4df441deb634211", + "0xe66c0f55f66c752edf73027d45b7b1ae729ae15e1c67c362dbc6f25edf8d76ff" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xe54f074c81bfa60b5bf413934c108086298b77291560edfeead8aa1232e95236" : "0x0f40aaa24323c9e6983ccffafeebe4b426509b901e8c98b8a40d881804804e6b", + "0xdc22d3171b82817c910bbeac1f8b50c8de99f8c524f172aef3491981bd5ed4fb" : "0x94b8cba4ea090d1c392fbc94b82fb9ef9f468a15bbc537f4d051776f4d422b1d", + "0x1b37e91bf8580c7c6bcf8cdff25c7ed78180124a94af6f30c40d476a3d079ad6" : "0xaba4cd295118a482a0a62579e35e4ba5bdd76146cc9e4d96172fce8be8977ab4", + "0xbf30cdcb83ab2bd5f5eee691ffa4107b58b75ba6a5c2e6754d4c5c0437f2876c" : "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x34cabe0c7e64a2caa93fd8d6a0defc07acb9d44b13430fa3ae9282fffd40dee4" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x58da0c0c256bba101ce36fad8bf838717a57e6ab850a191dc9c09da9ce56bf1b" : "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x34cabe0c7e64a2caa93fd8d6a0defc07acb9d44b13430fa3ae9282fffd40dee3" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x9001f91ddaef87bc067886e874c0749998c9b58b2ec8472ca014ca8b55f88578" : "0x0fb76974eefca01f33fb38646c2d3c1536f1a763d7aff53ab7f877d4c5ea7fd0", + "0x7e95f3cc3315d289c52253baaba29b1b00c86816e6b788d50795279a8baa00db" : "0x45e9723e9232b37207ecac1c97b8647d053625a578d450f7456280b2ff8efc27", + "0xe983d899f807bbcb5881f2ddf875b2ebb5cb8a7a4e77a8c98a40aaae6a468735" : "0x6d0be832b2007ea28cda705b73922cbf9794c5a25b89bd2f28b7347ed2b96c86", + "0x34cabe0c7e64a2caa93fd8d6a0defc07acb9d44b13430fa3ae9282fffd40dee2" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xaffe808b495d13a14391ce5f27c211c36da12826969cd7841ee0d81e5b900e2e" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x69ad1d19e617936abdf05133bf268dc8ced6b518f22b249b5860967d07006487" : "0x8c803b48b383ddabd1b3afe858efb48c203229b7317dd76149dddab4253b858a", + "0xbb3bc1a2015123750df57d4ceff7e28cb847910b79b34841de905b59a8bb177c" : "0x734417eb19e1873427257f1ea1594748c16cfa866a7b7cf896e281f2ec774a40", + "0xf60fa6e25e9028a6dc6b26bbc1eadae3da157df0d1d6f6628bc33cad68a7e455" : "0x2d7d00618c059ebe40593b9497c633e1ac6e161dadbd5bb734c2663cd3e8a8e1", + "0x41e9a54b3ee0c276aa076babb161de12b0f8916b47f8f6fb85cc387cf34696dd" : "0x22f2f444ebda9d2913ffef5059b039ec9b5876aa71821991c2515bf79f64935e", + "0xd2c8cbb562fccd0c9a3d0d491b7f65cc6a89856498f933427d9d21b745b9d50e" : "0x3625a26fdb7b747501f1ee2500f98c49d9cd290383a21254587c3c49d2805321", + "0x9ed0cedd2a9a78d949f40019f53d10031aef6ed342c97e01fc03b481ee56b3cb" : "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x696664a5f0ab5acd9304a377fb684f2d3fe6bb60b8a95cb2bdbb57db767e7a84" : "0x154cf60e137c594516a065149610b6a3989396a42581d5fd8919e711c55da225", + "0xdce8adbdefa929dbe60245f359446db4174c62824b42e5d4d9e7b834b4d61deb" : "0x2c9069845b2e74c577ff1cd18df6bc452805f527a9ee91fd4a059e0408b5dea6", + "0x45ceb8da6fb8936592d3bce4883f1a6a34d636f559e0a1070a5802a65ac39bd5" : "0x57a5122ff3bf737b0de0f9f08011a8648c19e43ff071fb7086234723c9383f1f", + "0xdd9493073db9e42fd955e834c89a74089f99196186ee0b2688124989be00d198" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xdd9493073db9e42fd955e834c89a74089f99196186ee0b2688124989be00d197" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x39050607fe892059a6344ab0f594f382fb0b345cab373497246dbe86fe7e14e7" : "0x2b3bca833e482737e7e47b1568e6f890f8e1666490d38fe130abd6f0ccb109cf", + "0x2bf9fd8facdd6fd9c84657f5ad7381a5aecf670cda68cb3c5829b6532c865506" : "0x53098a1d111586dbcc0d051846284f5803c63c313e7f7e6d84430435d11d4c50", + "0x7a9dcee62e3e02cc8e020f372df2efdeb835f091c1ef1dbe221072d1095aabd2" : "0x00000000000000000000000000000000000000000000002f0000000000000000", + "0xdd9493073db9e42fd955e834c89a74089f99196186ee0b2688124989be00d196" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xba8d79990898383919e437f2458b93b340072c89d963808d9e04f51858e3c5ec" : "0x41d2cac534d90a0dbd199117481a63e32cc11411dab2eaa36c91c0eec62823cf", + "0x70b3bf53996fac325eb67608a4eeb0cd0b55def6255d7ed42ad28ec07238b5d6" : "0x45e9723e9232b37207ecac1c97b8647d053625a578d450f7456280b2ff8efc27", + "0xd66f52a4e24585238ccc03443b2fdb8b2b100259bc7260f39097c7c339211ffe" : "0x1641851904381915c86b60df7e288896fb5f8ebad65d594829fb9f2b59cd1da6", + "0xfd280ac5182d5b2366122f38acfa6dc471240ffde9d5feb985ce7a2325c960e7" : "0x0000000000000000000000000000000000000000000000000000000000000003", + "0x34cabe0c7e64a2caa93fd8d6a0defc07acb9d44b13430fa3ae9282fffd40dee5" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x4aa6b934608a45c8f53a945c05ddee1814a3b9f63a048fc7ad3d47e67156f024" : "0xd03862becedada67b4825a0238f3e67495ccb595cd7d08f1bd5d3160644b9299", + "0xf043b5a1952847579f233706a8f130889a484d2da3e574fdd5859f05aaf52111" : "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x1489023d18c5d10427c4aa8dc726e840eb5ae7f604a8e9243c61634fb009e4d8" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xc98339d275eef16e0562ca8521212cef61aa0f39b12e2a27502aaa97a9e5e70f" : "0x5a3de2a5c268cdb75f4b01507aa80c4e4a1bc67bcb0df265bbb00060774e5978", + "0x1489023d18c5d10427c4aa8dc726e840eb5ae7f604a8e9243c61634fb009e4d7" : "0x0000000000000000000000000000000000000000000000000000000000000005", + "0x5cb38b16db1d632086d4af695de7f5f242a6e40947067f96edd566fe2ac438ef" : "0x6d0be832b2007ea28cda705b73922cbf9794c5a25b89bd2f28b7347ed2b96c86", + "0x3379e7ae125c5c5d623d1d993c1459b61d6723b1c30d1aa026c48f6a6155b8ea" : "0x8c4183732567a99a8a718e363391e102532f9a640e42968cf2354d9acc908bb0", + "0xed7d6e2d40fbd5046412ffad1c45b63d87c6197182d6dbc66bb1e5c6e4ded5c7" : "0xaba4cd295118a482a0a62579e35e4ba5bdd76146cc9e4d96172fce8be8977ab4", + "0xdd9493073db9e42fd955e834c89a74089f99196186ee0b2688124989be00d199" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x4b8b58f0b0e326a5907d1a810e5ff31e05b4cab45125b776db8577e7dbc46bce" : "0x00000000000000000000000000000000000000000000002f0000000000000000", + "0x3111bfd25728c0adfad0f8c1ad79cb1b91167267deca98de88f156ed25caeedc" : "0xad393086f30b49511b08fdd27ac78810b084c7cd7de6ac354f614c18ea9e7df4", + "0xd8f720c05a5526dd621d1831ae122abddd3dfecd8b63b0ba4c92fa7b2ade44ff" : "0xad393086f30b49511b08fdd27ac78810b084c7cd7de6ac354f614c18ea9e7df4", + "0x4c33460347337bfc7df08bf182988301b7b426a27a67f1c6c634f637c60e87ac" : "0xbab4ab2ad4eafe7c84ef6a8cd69157d9ce6b843793a2cd0877b8e91f63cb2d4d", + "0xf40f4cfdacb62dd799f36b580349fac1f4a4caf8dd3383cc387c35adb6574e21" : "0x00000000000000000000000000000000000000000000002f0000000000000000", + "0xb4a2b68c48ef78aeb641ee538fad51781022fd23ed9d93d211017db6a02376ce" : "0x0fbc06642245cf2fed7ed46ea0a18a7185830b6f2c4e0a4ca55246041e8bfa72", + "0x64a9621cc4ba92bf738c55010c609dfaa3972a1138c30b5adcef1ba2363b360e" : "0xd7953bfe8cb591f129fd0862a9e9c421151e2b5831560ff5215d23f751364b35", + "0x8da187157087529ee4e9c381f8e3149c56acf3bdfda29b8b9b4532f24b83f5fe" : "0x8c4183732567a99a8a718e363391e102532f9a640e42968cf2354d9acc908bb0", + "0x7e4d8c0f6d8abb4ce1ae45b254046aceedabfa9548851b8b5d3e2c0637c985fd" : "0x000000000000000000000000000000000000000000000000000000000000000b", + "0xaffe808b495d13a14391ce5f27c211c36da12826969cd7841ee0d81e5b900e2d" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xdd9493073db9e42fd955e834c89a74089f99196186ee0b2688124989be00d19a" : "0x0000000000000000000000000000000000000000000000000000000000000001" + } + }, + "e509e3a93beb1eba72f8cb8d25f93a85e2d54afb" : { + "balance" : "0", + "code" : "0x6000610b7f537c01000000000000000000000000000000000000000000000000000000006000350473c9ae5868651bf7b7db6e360217db49ce4e69c07e6020526308d3d58781141561024557600435606052606060605990590160009052600081526060518160200152600181604001528090502054608052600060806080599059016000905260008152606051816020015260028160400152328160600152809050205414151561014e57608060805990590160009052600081526060518160200152600281604001523281606001528090502054608052682f000000000000000060a060a059905901600090526000815260605181602001526000816040015260805181606001526000816080015280905020553260a060a05990590160009052600081526060518160200152600081604001526080518160600152600181608001528090502055610238565b608051608060805990590160009052600081526060518160200152600281604001523281606001528090502055682f000000000000000060a060a059905901600090526000815260605181602001526000816040015260805181606001526000816080015280905020553260a060a059905901600090526000815260605181602001526000816040015260805181606001526001816080015280905020556001606060605990590160009052600081526060518160200152600181604001528090502054016060606059905901600090526000815260605181602001526001816040015280905020555b60016101e05260206101e0f35b6328c8b31581141561029d576004356060526024356102005260a060a0599059016000905260008152606051816020015260008160400152610200518160600152600081608001528090502054610220526020610220f35b6374af23ec8114156103865760043560605260243561026052608060805990590160009052600081526060518160200152600281604001526102605181606001528090502054610200526000610200511415610332576102605160a060a05990590160009052600081526060518160200152600081604001526102005181606001526001816080015280905020541415610335565b60005b156103475760006102c05260206102c0f35b60a060a05990590160009052600081526060518160200152600081604001526102005181606001526000816080015280905020546102e05260206102e0f35b6384d646ee8114156103dc5760043560605260243560805260a060a05990590160009052600081526060518160200152600081604001526080518160600152600181608001528090502054610320526020610320f35b63f42294278114156106f45760043561026052601c602459905901600090520163175c6322601c82035260206103a06004836000602051602d5a03f1506103a0519050610360526102605115610581576103605160020280602002602001599059016000905281815260208101905090506103c05261036051806020026020015990590160009052818152602081019050905061042052601c602459905901600090520163c3387858601c8203526103605160408160200201599059016000905281602002604001816004856000602051602d5a03f150604081019050905090506104205260006104c05260006104e0525b610360516104c051121561057c576104c051602002610420510151606052601c60645990590160009052016374af23ec601c82035260605160048201526102605160248201526020610520604483600030602d5a03f1506105205190506105005260006105005114151561056c576060516104e0516020026103c05101526105005160016104e051016020026103c051015260026104e051016104e0525b60016104c051016104c0526104ce565b6106d7565b32610260526103605160020280602002602001599059016000905281815260208101905090506103c05261036051806020026020015990590160009052818152602081019050905061042052601c602459905901600090520163c3387858601c8203526103605160408160200201599059016000905281602002604001816004856000602051602d5a03f150604081019050905090506104205260006104c05260006104e0525b610360516104c05112156106d6576104c051602002610420510151606052601c60645990590160009052016374af23ec601c820352606051600482015261026051602482015260206105c0604483600030602d5a03f1506105c0519050610500526000610500511415156106c6576060516104e0516020026103c05101526105005160016104e051016020026103c051015260026104e051016104e0525b60016104c051016104c052610628565b5b6103c05160206040820352602060208203510260400160408203f3505b6380b5e7bd81141561073557600435606052606060605990590160009052600081526060518160200152600181604001528090502054610600526020610600f35b63156f1c328114156107865760043560605260243561064052608060805990590160009052600081526060518160200152600281604001526106405181606001528090502054610660526020610660f35b63b3a24fc081141561087857365990590160009052366004823760043560208201016106c0526024356106e05250600260206106c0510351018060200260200159905901600090528181526020810190509050610700523261070051526106e051602061070051015260026104c0525b600260206106c0510351016104c05112156108385760026104c051036020026106c05101516104c05160200261070051015260016104c051016104c0526107f6565b60206107005103516020026020599059016000905260208183610700516000600287604801f15080519050905061076052610760516107c05260206107c0f35b63e346f5fc811415610a1c576004356107e0526024356108005260006104c0525b606060605990590160009052600081526107e05181602001526001816040015280905020546104c05112156109e65760a060a05990590160009052600081526107e0518160200152600081604001526104c0518160600152600181608001528090502054610840526108405160a060a0599059016000905260008152610800518160200152600081604001526104c051816060015260018160800152809050205560a060a05990590160009052600081526107e0518160200152600081604001526104c051816060015260008160800152809050205460a060a0599059016000905260008152610800518160200152600081604001526104c05181606001526000816080015280905020556104c0516080608059905901600090526000815261080051816020015260028160400152610840518160600152809050205560016104c051016104c052610899565b6104c051606060605990590160009052600081526108005181602001526001816040015280905020556001610920526020610920f35b633fb57036811415610b5457600435606052602435610940526060606059905901600090526000815260605181602001526001816040015280905020546109605261096051608060805990590160009052600081526060518160200152600281604001526109405181606001528090502055600060a060a05990590160009052600081526060518160200152600081604001526109605181606001526000816080015280905020556109405160a060a05990590160009052600081526060518160200152600081604001526109605181606001526001816080015280905020556001606060605990590160009052600081526060518160200152600181604001528090502054016060606059905901600090526000815260605181602001526001816040015280905020556001610a40526020610a40f35b6312709a33811415610beb57600435606052602435608052604435610a6052610a605160a060a059905901600090526000815260605181602001526000816040015260805181606001526000816080015280905020540160a060a059905901600090526000815260605181602001526000816040015260805181606001526000816080015280905020556001610ac0526020610ac0f35b633229cf6e811415610c8257600435606052602435608052604435610a6052610a605160a060a059905901600090526000815260605181602001526000816040015260805181606001526000816080015280905020540360a060a059905901600090526000815260605181602001526000816040015260805181606001526000816080015280905020556001610b20526020610b20f35b63a75f5c6a811415610ce557600435606052602435608052604435610a6052610a605160a060a059905901600090526000815260605181602001526000816040015260805181606001526000816080015280905020556001610b60526020610b60f35b50", + "nonce" : "0", + "storage" : { + "0xec5e7f54fa5e516e616b04f9d5a0ee433a80e09ed47d7e5269afd76c05ff251e" : "0x0000000000000000000000000000000000000000000000000000000000000002", + "0xaf1d6676be3ab502a59d91f6f5c49baffc15b2cfc65a41c4d96857c0f535adba" : "0x0000000000000000000000000000000000000000000001d60000000000000000", + "0xdf1a770f69d93d1719292f384fdb4da22c0e88aef2ba462bff16674bc7848730" : "0x0000000000000000000000001c11aa45c792e202e9ffdc2f12f99d0d209bef70", + "0x0f299dbbe3a7a5d949fe794e9a47b3106699c8110ff986eb84921c183e69e7f0" : "0x00000000000000000000000000000000000000000000002f0000000000000000", + "0x689082d076ec3c02cbe4b99f6d9833e3c4a161072fd42fb7649eee5189a67ccc" : "0x00000000000000000000000063524e3fe4791aefce1e932bbfb3fdf375bfad89", + "0x1edcd36f61cae5dc6414157dfbadf9f11ca013ac763e27f8af55feaa8a239c89" : "0x0000000000000000000000000000000000000000000000000000000000000001" + } + }, + "9761fecf88590592cf05ce545504d376d1693ab3" : { + "balance" : "0", + "code" : "0x60006105df537c010000000000000000000000000000000000000000000000000000000060003504730ea65418d7bf32680f55572c943a94b59080499860205273e509e3a93beb1eba72f8cb8d25f93a85e2d54afb60405273c9ae5868651bf7b7db6e360217db49ce4e69c07e60605273f1562e1c0d0baa3ea746442bb7f11153fcf5cfda60805263546fdeb381141561038d5760043560c05260243560e05260443561010052606435610120526084356101405260026101005101601c606459905901600090520163e05dcb56601c82035260c051600482015260e05160248201526002610100510160408160200201599059016000905281602002604001816044856000602051602d5a03f150604081019050905090506000600161010051016020028201511415610250576060601c61014c59905901600090520163e365736b601c82035260c051600482015260e0516024820152601c6084599059016000905201632f300bee601c82035260026004820152600560248201526101005160448201528460408160200201599059016000905281602002604001816064856000608051602d5a03f1506040810190509050905060208103516020026020018360448401526020820360a4840152806101088401528084019350505081600401599059016000905260648160648460006004601cf16101fc57fe5b6064810192506101088201518080858260a487015160006004600a8705601201f161022357fe5b50808401935050808303602061028082846000602051602d5a03f15061028051905090509050905061037d565b6060601c61014c59905901600090520163e365736b601c82035260c051600482015260e0516024820152601c6084599059016000905201632f300bee601c820352600160016101005101602002850151036004820152600560248201526101005160448201528460408160200201599059016000905281602002604001816064856000608051602d5a03f1506040810190509050905060208103516020026020018360448401526020820360a4840152806101088401528084019350505081600401599059016000905260648160648460006004601cf161032d57fe5b6064810192506101088201518080858260a487015160006004600a8705601201f161035457fe5b5080840193505080830360206102c082846000602051602d5a03f1506102c05190509050905090505b5060016102e05260206102e0f350505b63de9080c88114156107645760043560c05260243560e05260443561010052606435610120526084356101405260026101005101601c606459905901600090520163e05dcb56601c82035260c051600482015260e05160248201528160408160200201599059016000905281602002604001816044856000602051602d5a03f15060408101905090509050601c6064599059016000905201632c5a40d5601c82035260c051600482015260e05160248201526101405160408160200201599059016000905281602002604001816044856000602051602d5a03f1506040810190509050905061012051806020026020015990590160009052818152602081019050905060005b610120518112156104ee57601c60645990590160009052016328c8b315601c82035260c051600482015281602482015260206103606044836000604051602d5a03f15061036051905081602002830152600181019050610493565b5060a0601c61020c59905901600090520163a647a5b9601c8203528460208103516020026020018360048401526020820360a484015280610148840152808401935050508360208103516020026020018360248401526020820360c484015280610168840152808401935050508260208103516020026020018360448401526020820360e4840152806101888401528084019350505061012051606482015261010051608482015281600401599059016000905260a48160a484600060046022f16105b557fe5b60a4810192506101488201518080858260a487015160006004600a8705601201f16105dc57fe5b508084019350506101688201518080858260c487015160006004600a8705601201f161060457fe5b508084019350506101888201518080858260e487015160006004600a8705601201f161062c57fe5b5080840193505080830387604081602002015990590160009052816020026040018184866000608051602d5a03f1506040810190509050905090509050905092506060601c61014c59905901600090520163e365736b601c82035260c051600482015260e05160248201528460208103516020026020018360448401526020820360a4840152806101088401528084019350505081600401599059016000905260648160648460006004601cf16106df57fe5b6064810192506101088201518080858260a487015160006004600a8705601201f161070657fe5b5080840193505080830360206103c082846000602051602d5a03f1506103c05190509050905090505060006101005160200284015114156107525760006103e05260206103e0f361075f565b6001610400526020610400f35b505050505b63384ca8dd811415610a665760043560c05260243560e052604435610100526064356101205260843561014052601c606459905901600090520163e05dcb56601c82035260c051600482015260e05160248201526002610100510160408160200201599059016000905281602002604001816044856000602051602d5a03f15060408101905090509050601c606459905901600090520163fa9832d1601c82035260c051600482015260e05160248201526101005160408160200201599059016000905281602002604001816044856000602051602d5a03f15060408101905090509050601c608459905901600090520163aad7d6e3601c82035260c051600482015260e05160248201526060601c61014c599059016000905201635b180229601c8203528360208103516020026020018360048401526020820360648401528060c8840152808401935050508460208103516020026020018360248401526020820360848401528060e88401528084019350505061010051604482015281600401599059016000905260648160648460006004601cf161090157fe5b60648101925060c882015180808582606487015160006004600a8705601201f161092757fe5b5080840193505060e882015180808582608487015160006004600a8705601201f161094e57fe5b50808401935050808303602061044082846000608051602d5a03f150610440519050905090509050604482015260206104606064836000602051602d5a03f150610460519050506060601c61014c59905901600090520163222a8663601c82035260c051600482015260e05160248201528260208103516020026020018360448401526020820360a4840152806101088401528084019350505081600401599059016000905260648160648460006004601cf1610a0757fe5b6064810192506101088201518080858260a487015160006004600a8705601201f1610a2e57fe5b50808401935050808303602061048082846000602051602d5a03f1506104805190509050905090505060016104a05260206104a0f350505b63d5dc5af1811415610d4b5760043560c05260243560e052604435610100526064356101205260843561014052601c606459905901600090520163e05dcb56601c82035260c051600482015260e05160248201526002610100510160408160200201599059016000905281602002604001816044856000602051602d5a03f15060408101905090509050601c6064599059016000905201632c5a40d5601c82035260c051600482015260e05160248201526101405160408160200201599059016000905281602002604001816044856000602051602d5a03f150604081019050905090506080601c6101ac59905901600090520163f4ca7dc4601c82035283602081035160200260200183600484015260208203608484015280610108840152808401935050508260208103516020026020018360248401526020820360a4840152806101288401528084019350505061012051604482015261010051606482015281600401599059016000905260848160848460006004601ff1610be757fe5b60848101925061010882015180808582608487015160006004600a8705601201f1610c0e57fe5b508084019350506101288201518080858260a487015160006004600a8705601201f1610c3657fe5b5080840193505080830361014051604081602002015990590160009052816020026040018184866000608051602d5a03f1506040810190509050905090509050905090506060601c61014c59905901600090520163b39e1faa601c82035260c051600482015260e05160248201528260208103516020026020018360448401526020820360a4840152806101088401528084019350505081600401599059016000905260648160648460006004601cf1610cec57fe5b6064810192506101088201518080858260a487015160006004600a8705601201f1610d1357fe5b5080840193505080830360206104c082846000602051602d5a03f1506104c05190509050905090505060016104e05260206104e0f350505b630939aa8c81141561114c5760043560c05260243560e052604435610100526064356101205260843561014052601c606459905901600090520163e05dcb56601c82035260c051600482015260e05160248201526002610100510160408160200201599059016000905281602002604001816044856000602051602d5a03f15060408101905090509050601c6064599059016000905201637dc12195601c82035260c051600482015260e05160248201526101405160408160200201599059016000905281602002604001816044856000602051602d5a03f15060408101905090509050601c606459905901600090520163586b5be0601c82035260c051600482015260e051602482015260206105006044836000602051602d5a03f150610500519050601c606459905901600090520163eb8af5aa601c82035260c051600482015260e05160248201526101205160408160200201599059016000905281602002604001816044856000602051602d5a03f1506040810190509050905060c0601c61026c59905901600090520163232b2734601c8203528260208103516020026020018360048401526020820360c484015280610188840152808401935050508560208103516020026020018360248401526020820360e4840152806101a88401528084019350505084602081035160200260200183604484015260208203610104840152806101c8840152808401935050508360648201526101205160848201526101005160a482015281600401599059016000905260c48160c484600060046025f1610f9657fe5b60c4810192506101888201518080858260c487015160006004600a8705601201f1610fbd57fe5b508084019350506101a88201518080858260e487015160006004600a8705601201f1610fe557fe5b508084019350506101c88201518080858261010487015160006004600a8705601201f161100e57fe5b5080840193505080830361012051604081602002015990590160009052816020026040018184866000608051602d5a03f1506040810190509050905090509050905090506060601c61014c5990590160009052016301112b27601c82035260c051600482015260e05160248201528260208103516020026020018360448401526020820360a4840152806101088401528084019350505081600401599059016000905260648160648460006004601cf16110c457fe5b6064810192506101088201518080858260a487015160006004600a8705601201f16110eb57fe5b50808401935050808303602061058082846000602051602d5a03f15061058051905090509050905050600060016101005101602002850151141561113a5760006105a05260206105a0f3611147565b60016105c05260206105c0f35b505050505b50", + "nonce" : "0", + "storage" : { + } + }, + "f1562e1c0d0baa3ea746442bb7f11153fcf5cfda" : { + "balance" : "0", + "code" : "0x600061067f537c010000000000000000000000000000000000000000000000000000000060003504632f300bee8114156100ac576004356040526024356060526044356080526002608051018080602002602001599059016000905281815260208101905090506801000000000000000081526060516080516020028201526001604051036001608051016020028201528060206040820352602060208203510260400160408203f35050505b63a647a5b98114156102c85736599059016000905236600482376004356020820101610100526024356020820101610160526044356020820101610180526064356101a05260843560805250602061010051035180806020026020015990590160009052818152602081019050905060005b6101a0518112156101d557600060005b608051811215610162578060200261010051015181608051850201602002610160510151028201915060018101905061012e565b50680100000000000000008105905060005b6080518112156101c857700100000000000000000000000000000000836020026101805101518260805186020160200261016051015184020205816020028501510381602002850152600181019050610174565b505060018101905061011e565b50600060005b60805181121561020357806020028301518160200284015102820191506001810190506101db565b5068010000000000000000810590506002810560005b600b81121561024257600282680100000000000000008502058301059150600181019050610219565b5060005b60805181121561027657816801000000000000000082602002860151020581602002850152600181019050610246565b5050506001608051602002610100510151036080516020028201526001608051016020026101005101516001608051016020028201528060206040820352602060208203510260400160408203f35050505b635b18022981141561037957365990590160009052366004823760043560208201016103005260243560208201016103205260443560805250600060005b60805181121561033f57680100000000000000008160200261032051015182602002610300510151020582019150600181019050610306565b6000610320515114151561036657610320515168010000000000000000830205915061036b565b600091505b81610380526020610380f350505b63f4ca7dc481141561057157365990590160009052366004823760043560208201016103a05260243560208201016103c0526044356101a0526064356080525060206103c051035160026080510a806020026020015990590160009052818152602081019050905060005b60805181121561044d5760005b6080518112156104415768010000000000000000816020026103a0510151836020026103a051015102058160805184020160200284015101816080518402016020028401526001810190506103f1565b506001810190506103e4565b81905090508180602002602001599059016000905281815260208101905090506080516101a05102806020026020015990590160009052818152602081019050905060005b6101a05181121561051e5760005b6080518112156105125760005b608051811215610506576801000000000000000082608051830201602002870151826080518602016020026103c051015102058260805185020160200285015101826080518502016020028501526001810190506104ad565b506001810190506104a0565b50600181019050610492565b819050905060005b848112156105525780602002820151816020026103c05101510381602002840152600181019050610526565b508160206040820352602060208203510260400160408203f350505050505b63232b273481141561069d57365990590160009052366004823760043560208201016106205260243560208201016102805260443560208201016103c052606435610640526084356101a05260a435608052506000610280515112156106025760005b6080518112156106005780602002610280510151600003816020026102805101526001810190506105d4565b505b60005b6101a05181121561067f5760005b60805181121561067357680100000000000000006801000000000000000082602002610280510151610640510205826080518502016020026103c05101510205826020026106205101510182602002610620510152600181019050610613565b50600181019050610605565b6106205160206040820352602060208203510260400160408203f350505b50", + "nonce" : "0", + "storage" : { + } + }, + "1cdc8315bdb1362de8b7b2fa9ee75dc873037179" : { + "balance" : "0x01", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "0000000000000000000000000000000000000001" : { + "balance" : "0x01", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "0000000000000000000000000000000000000002" : { + "balance" : "0x01", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "0000000000000000000000000000000000000003" : { + "balance" : "0x01", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "0000000000000000000000000000000000000004" : { + "balance" : "0x01", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "0000000000000000000000000000000000000000" : { + "balance" : "0x01", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "4000000000000000000000", + "code" : "0x", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : { + "data" : "0x36a560bd00000000000000000000000000000000000000000000000000000000000f69b5", + "gasLimit" : "3000000", + "gasPrice" : "10000000000000", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "b03f030056db7d467d778326658bac0d1b35d8f7", + "value" : "0" + } } } From e9748677df6463b3bebb304bbad609fee5f1fa01 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 14 Jun 2015 06:19:29 +0200 Subject: [PATCH 005/103] ImportRoute struct instead of class --- libethereum/BlockChain.cpp | 8 ++++---- libethereum/BlockChain.h | 14 +++----------- libethereum/Client.cpp | 13 ++++++------- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b76ec591e..83275045c 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -326,8 +326,8 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st ImportRoute r; DEV_TIMED_ABOVE(Block import, 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); - fresh += r.liveBlocks(); - dead += r.deadBlocks(); + fresh += r.liveBlocks; + dead += r.deadBlocks; } catch (dev::eth::UnknownParent) { @@ -699,8 +699,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& dead.push_back(h); else fresh.push_back(h); - return ImportRoute(dead, fresh); -} + return ImportRoute{dead, fresh}; +}; void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) { diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index d865fd025..23137c38d 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -81,17 +81,9 @@ using BlocksHash = std::unordered_map; using TransactionHashes = h256s; using UncleHashes = h256s; -class ImportRoute -{ -public: - ImportRoute() {}; - ImportRoute(h256s const& _deadBlocks, h256s const& _liveBlocks): m_deadBlocks(_deadBlocks), m_liveBlocks(_liveBlocks) {}; - h256s const& deadBlocks() const { return m_deadBlocks; } - h256s const& liveBlocks() const { return m_liveBlocks; } - -private: - h256s m_deadBlocks; - h256s m_liveBlocks; +struct ImportRoute { + h256s deadBlocks; + h256s liveBlocks; }; enum { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index cd8cb6805..0177c6007 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -614,10 +614,9 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) void Client::syncBlockQueue() { cwork << "BQ ==> CHAIN ==> STATE"; - pair blocks; - tie(blocks.first, blocks.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 10 + 5); - ImportRoute ir(blocks.second, blocks.first); - if (ir.liveBlocks().empty()) + ImportRoute ir; + tie(ir.liveBlocks, ir.deadBlocks, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 10 + 5); + if (ir.liveBlocks.empty()) return; onChainChanged(ir); } @@ -659,7 +658,7 @@ void Client::syncTransactionQueue() void Client::onChainChanged(ImportRoute const& _ir) { // insert transactions that we are declaring the dead part of the chain - for (auto const& h: _ir.deadBlocks()) + for (auto const& h: _ir.deadBlocks) { clog(ClientNote) << "Dead block:" << h; for (auto const& t: m_bc.transactions(h)) @@ -670,7 +669,7 @@ void Client::onChainChanged(ImportRoute const& _ir) } // remove transactions from m_tq nicely rather than relying on out of date nonce later on. - for (auto const& h: _ir.liveBlocks()) + for (auto const& h: _ir.liveBlocks) { clog(ClientChat) << "Live block:" << h; for (auto const& th: m_bc.transactionHashes(h)) @@ -684,7 +683,7 @@ void Client::onChainChanged(ImportRoute const& _ir) h->noteNewBlocks(); h256Hash changeds; - for (auto const& h: _ir.liveBlocks()) + for (auto const& h: _ir.liveBlocks) appendFromNewBlock(h, changeds); // RESTART MINING From 821ba0e002a0af53c6c86c4f712d03bcb2f10a2d Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 14 Jun 2015 06:32:51 +0200 Subject: [PATCH 006/103] changed Blockchain sync return tuple from to --- libethereum/BlockChain.cpp | 4 ++-- libethereum/BlockChain.h | 2 +- libethereum/Client.cpp | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 83275045c..0a3be0f1b 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -305,7 +305,7 @@ LastHashes BlockChain::lastHashes(unsigned _n) const return m_lastLastHashes; } -tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) +tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) { // _bq.tick(*this); @@ -353,7 +353,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st badBlocks.push_back(block.verified.info.hash()); } } - return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); + return make_tuple(ImportRoute{dead, fresh}, _bq.doneDrain(badBlocks)); } pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 23137c38d..e3fcf83c1 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -116,7 +116,7 @@ public: /// Sync the chain with any incoming blocks. All blocks should, if processed in order. /// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting. - std::tuple sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); + std::tuple sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 0177c6007..70ef1e406 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -614,8 +614,9 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) void Client::syncBlockQueue() { cwork << "BQ ==> CHAIN ==> STATE"; + ImportRoute ir; - tie(ir.liveBlocks, ir.deadBlocks, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 10 + 5); + tie(ir, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 10 + 5); if (ir.liveBlocks.empty()) return; onChainChanged(ir); From 63fb8d89bd0b9112d6253cb817ee43c8f7a54d1a Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 14 Jun 2015 06:38:12 +0200 Subject: [PATCH 007/103] merge fix --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index a3294f3c7..9ce0cb5ac 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -629,7 +629,7 @@ void Client::syncBlockQueue() m_syncAmount = max(c_syncMin, m_syncAmount * 9 / 10); else if (elapsed < c_targetDuration * 0.9 && m_syncAmount < c_syncMax) m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1); - if (ir.first.empty()) + if (ir.liveBlocks.empty()) return; onChainChanged(ir); } From aca7c7c01e4731341d71106d67b7f5e208dbc002 Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 14 Jun 2015 08:28:05 +0200 Subject: [PATCH 008/103] enable syncing with rude peer --- libethereum/EthereumHost.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 67a21d36a..e69bfa684 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -758,10 +758,6 @@ bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const { - // Early exit if this peer has proved unreliable. - if (_peer->isRude()) - return false; - h256 c = m_chain.currentHash(); unsigned n = m_chain.number(); u256 td = m_chain.details().totalDifficulty; From c592fde8cf8481d77ffd5d3a97ad851d1c0c4008 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 03:22:55 +0200 Subject: [PATCH 009/103] style fix --- libethereum/BlockChain.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index e3fcf83c1..2d3abd922 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -81,7 +81,8 @@ using BlocksHash = std::unordered_map; using TransactionHashes = h256s; using UncleHashes = h256s; -struct ImportRoute { +struct ImportRoute +{ h256s deadBlocks; h256s liveBlocks; }; From 6ae2eb8039efc4427c0295f202c2c254a2804d3f Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 15 Jun 2015 04:39:44 +0200 Subject: [PATCH 010/103] removed extra ; --- libethereum/BlockChain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 0a3be0f1b..7386fa776 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -700,7 +700,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& else fresh.push_back(h); return ImportRoute{dead, fresh}; -}; +} void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) { From d416e667ed2cded424d4565bc4a0ecff240356a6 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 15 Jun 2015 12:18:49 +0200 Subject: [PATCH 011/103] Fix macosx opencl warnings It seems that OpenCL macosx implementation needs a static on the function implementations if there is no corresponding declaration as can be seen by this report: https://github.com/ethereum/cpp-ethereum/issues/2172 --- libethash-cl/ethash_cl_miner_kernel.cl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl index 2143435ed..8ea6df12d 100644 --- a/libethash-cl/ethash_cl_miner_kernel.cl +++ b/libethash-cl/ethash_cl_miner_kernel.cl @@ -36,7 +36,7 @@ __constant uint2 const Keccak_f1600_RC[24] = { (uint2)(0x80008008, 0x80000000), }; -void keccak_f1600_round(uint2* a, uint r, uint out_size) +static void keccak_f1600_round(uint2* a, uint r, uint out_size) { #if !__ENDIAN_LITTLE__ for (uint i = 0; i != 25; ++i) @@ -152,7 +152,7 @@ void keccak_f1600_round(uint2* a, uint r, uint out_size) #endif } -void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate) +static void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate) { for (uint i = in_size; i != 25; ++i) { @@ -194,17 +194,17 @@ void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate) #define countof(x) (sizeof(x) / sizeof(x[0])) -uint fnv(uint x, uint y) +static uint fnv(uint x, uint y) { return x * FNV_PRIME ^ y; } -uint4 fnv4(uint4 x, uint4 y) +static uint4 fnv4(uint4 x, uint4 y) { return x * FNV_PRIME ^ y; } -uint fnv_reduce(uint4 v) +static uint fnv_reduce(uint4 v) { return fnv(fnv(fnv(v.x, v.y), v.z), v.w); } @@ -227,7 +227,7 @@ typedef union uint4 uint4s[128 / sizeof(uint4)]; } hash128_t; -hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate) +static hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate) { hash64_t init; uint const init_size = countof(init.ulongs); @@ -243,7 +243,7 @@ hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate) return init; } -uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate) +static uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate) { uint4 mix = init; @@ -277,7 +277,7 @@ uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global -uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate) +static uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate) { uint4 mix = init; @@ -311,7 +311,7 @@ uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash12 } -hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate) +static hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate) { ulong state[25]; @@ -330,7 +330,7 @@ hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate) return hash; } -hash32_t compute_hash_simple( +static hash32_t compute_hash_simple( __constant hash32_t const* g_header, __global hash128_t const* g_dag, ulong nonce, @@ -383,7 +383,7 @@ typedef union } compute_hash_share; -hash32_t compute_hash( +static hash32_t compute_hash( __local compute_hash_share* share, __constant hash32_t const* g_header, __global hash128_t const* g_dag, @@ -427,7 +427,7 @@ hash32_t compute_hash( } -hash32_t compute_hash_chunks( +static hash32_t compute_hash_chunks( __local compute_hash_share* share, __constant hash32_t const* g_header, __global hash128_t const* g_dag, From 8357930b25e5e4914d84eba507b7d94885ff5966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 15 Jun 2015 14:07:59 +0200 Subject: [PATCH 012/103] Do not increase Windows stack size. --- cmake/EthCompilerSettings.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 53535a489..b48dae8f8 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -43,8 +43,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification # warning LNK4099: pdb was not found with lib - # stack size 16MB - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:33554432") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075") # windows likes static if (NOT ETH_STATIC) From a52d85c38d738ae65ffd771d1b162ea5467fea86 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 15 Jun 2015 14:31:01 +0200 Subject: [PATCH 013/103] fix block number in test --- test/libethereum/StateTestsFiller/stSpecialTestFiller.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libethereum/StateTestsFiller/stSpecialTestFiller.json b/test/libethereum/StateTestsFiller/stSpecialTestFiller.json index 60181bd5c..fb7a7aa8f 100644 --- a/test/libethereum/StateTestsFiller/stSpecialTestFiller.json +++ b/test/libethereum/StateTestsFiller/stSpecialTestFiller.json @@ -271,7 +271,7 @@ "currentCoinbase" : "1cdc8315bdb1362de8b7b2fa9ee75dc873037179", "currentDifficulty" : "21010229025", "currentGasLimit" : "3141592", - "currentNumber" : "504780", + "currentNumber" : "504980", "currentTimestamp" : 1, "previousHash" : "9ff4de714e01da9f8b61992efdab9b51ca14ac42d43f4c24df1d002a1239b1e9" }, From 402dc016408ac87fb53118e63f95196a4319efbf Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 15 Jun 2015 16:31:41 +0300 Subject: [PATCH 014/103] Coverage info --- cmake/EthCompilerSettings.cmake | 7 ++++ getcoverage.sh | 33 +++++++++++++++++++ ...reCompiledContractsTransactionFiller.json} | 0 test/libethereum/state.cpp | 4 +-- 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100755 getcoverage.sh rename test/libethereum/StateTestsFiller/{stPrecompiledContractsTransactionFiller.json => stPreCompiledContractsTransactionFiller.json} (100%) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 53535a489..4009b22a6 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -64,6 +64,13 @@ if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_C set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lprofiler") endif () +if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))) + set(CMAKE_CXX_FLAGS "-g --coverage ${CMAKE_CXX_FLAGS}") + set(CMAKE_C_FLAGS "-g --coverage ${CMAKE_C_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "--coverage ${CMAKE_SHARED_LINKER_FLAGS} -lprofiler") + set(CMAKE_EXE_LINKER_FLAGS "--coverage ${CMAKE_EXE_LINKER_FLAGS} -lprofiler") +endif () + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) option(USE_LD_GOLD "Use GNU gold linker" ON) if (USE_LD_GOLD) diff --git a/getcoverage.sh b/getcoverage.sh new file mode 100755 index 000000000..a04ab78fe --- /dev/null +++ b/getcoverage.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +CPP_ETHEREUM_PATH=$(pwd) + +if [ ! -d "$CPP_ETHEREUM_PATH/build/test" ]; then + echo "You need to compile and build ethereum with cmake -DPROFILING option to the build dir!" + exit; +fi + +if which lcov >/dev/null; then + if which genhtml >/dev/null; then + echo Running testeth... + $($CPP_ETHEREUM_PATH/build/test/testeth) + echo Prepearing coverage info... + else + echo genhtml not found + exit; + fi +else + echo lcov not found + exit; +fi + +OUTPUT_DIR="$CPP_ETHEREUM_PATH/build/test/coverage" + +TESTETH=$CPP_ETHEREUM_PATH/build/test/CMakeFiles/testeth.dir +lcov --capture --directory $TESTETH --output-file $OUTPUT_DIR/coverage.info +genhtml $OUTPUT_DIR/coverage.info --output-directory $OUTPUT_DIR/testeth + +echo "Coverage info should be located at: $CPP_ETHEREUM_PATH/build/test/coverage/testeth" +echo "Opening index..." + +xdg-open $CPP_ETHEREUM_PATH/build/test/coverage/testeth/index.html diff --git a/test/libethereum/StateTestsFiller/stPrecompiledContractsTransactionFiller.json b/test/libethereum/StateTestsFiller/stPreCompiledContractsTransactionFiller.json similarity index 100% rename from test/libethereum/StateTestsFiller/stPrecompiledContractsTransactionFiller.json rename to test/libethereum/StateTestsFiller/stPreCompiledContractsTransactionFiller.json diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index 5eb3c76c3..632e7982b 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -129,9 +129,9 @@ BOOST_AUTO_TEST_CASE(stPreCompiledContracts) dev::test::executeTests("stPreCompiledContracts", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); } -BOOST_AUTO_TEST_CASE(stPrecompiledContractsTransaction) +BOOST_AUTO_TEST_CASE(stPreCompiledContractsTransaction) { - dev::test::executeTests("stPrecompiledContractsTransaction", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); + dev::test::executeTests("stPreCompiledContractsTransaction", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); } BOOST_AUTO_TEST_CASE(stLogTests) From 1959b140f9a628ec48fae59f195392465b0415fa Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 15 Jun 2015 18:27:00 +0300 Subject: [PATCH 015/103] Coverage script --- getcoverage.sh | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/getcoverage.sh b/getcoverage.sh index a04ab78fe..4c01bad46 100755 --- a/getcoverage.sh +++ b/getcoverage.sh @@ -7,8 +7,12 @@ if [ ! -d "$CPP_ETHEREUM_PATH/build/test" ]; then exit; fi +OUTPUT_DIR="$CPP_ETHEREUM_PATH/build/test/coverage" +TESTETH=$CPP_ETHEREUM_PATH/build #/test/CMakeFiles/testeth.dir + if which lcov >/dev/null; then if which genhtml >/dev/null; then + lcov --directory $TESTETH --zerocounters echo Running testeth... $($CPP_ETHEREUM_PATH/build/test/testeth) echo Prepearing coverage info... @@ -21,13 +25,15 @@ else exit; fi -OUTPUT_DIR="$CPP_ETHEREUM_PATH/build/test/coverage" - -TESTETH=$CPP_ETHEREUM_PATH/build/test/CMakeFiles/testeth.dir -lcov --capture --directory $TESTETH --output-file $OUTPUT_DIR/coverage.info -genhtml $OUTPUT_DIR/coverage.info --output-directory $OUTPUT_DIR/testeth +echo Cleaning previous report... +rm -r $OUTPUT_DIR/testeth +rm $OUTPUT_DIR/full_coverage.info +rm $OUTPUT_DIR/testeth_coverage.info +lcov --capture --directory $TESTETH --output-file $OUTPUT_DIR/full_coverage.info +lcov --extract $OUTPUT_DIR/full_coverage.info *cpp-ethereum/* --output-file $OUTPUT_DIR/testeth_coverage.info +genhtml $OUTPUT_DIR/testeth_coverage.info --output-directory $OUTPUT_DIR/testeth echo "Coverage info should be located at: $CPP_ETHEREUM_PATH/build/test/coverage/testeth" echo "Opening index..." -xdg-open $CPP_ETHEREUM_PATH/build/test/coverage/testeth/index.html +xdg-open $CPP_ETHEREUM_PATH/build/test/coverage/testeth/index.html & From 1c2a9cd088d4e072e064a05aece206159137d471 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 15 Jun 2015 19:01:16 +0200 Subject: [PATCH 016/103] fixed syncing stalling issues --- libethereum/EthereumHost.cpp | 38 ++++++++++++++++++++++++------------ libethereum/EthereumPeer.cpp | 1 + 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index e69bfa684..b10e74f22 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -292,8 +292,8 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer) else _peer->m_expectedHashes = estimatedHashes; continueSync(_peer); + DEV_INVARIANT_CHECK; } - DEV_INVARIANT_CHECK; } unsigned EthereumHost::estimateHashes() @@ -313,6 +313,7 @@ unsigned EthereumHost::estimateHashes() void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; if (_peer->m_syncHashNumber > 0) _peer->m_syncHashNumber += _hashes.size(); @@ -322,7 +323,6 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete) { - DEV_INVARIANT_CHECK; if (_hashes.empty()) { _peer->m_hashSub.doneFetch(); @@ -454,7 +454,8 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) unsigned unknown = 0; unsigned got = 0; unsigned repeated = 0; - h256 lastUnknown; + u256 maxDifficulty = 0; + h256 maxUnknown; for (unsigned i = 0; i < itemCount; ++i) { @@ -483,9 +484,17 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) break; case ImportResult::UnknownParent: - lastUnknown = h; + { unknown++; + BlockInfo bi; + bi.populateFromHeader(_r[i][0]); + if (bi.difficulty > maxDifficulty) + { + maxDifficulty = bi.difficulty; + maxUnknown = h; + } break; + } default:; } @@ -501,8 +510,10 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) if (m_state == SyncState::NewBlocks && unknown > 0) { - _peer->m_latestHash = lastUnknown; - resetSyncTo(lastUnknown); + _peer->m_latestHash = maxUnknown; + _peer->m_totalDifficulty = maxDifficulty; + if (peerShouldGrabChain(_peer)) + resetSyncTo(maxUnknown); } continueSync(_peer); @@ -528,7 +539,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; - if ((isSyncing() || _peer->isConversing()) && m_state != SyncState::NewBlocks) + if ((isSyncing() || _peer->isConversing())) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -565,11 +576,14 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) u256 difficulty = _r[1].toInt(); if (m_syncingTotalDifficulty < difficulty) { - clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; _peer->m_latestHash = h; _peer->m_totalDifficulty = difficulty; - resetSyncTo(h);; - sync = true; + if (peerShouldGrabChain(_peer)) + { + clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; + resetSyncTo(h);; + sync = true; + } } } break; @@ -580,7 +594,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) _peer->m_knownBlocks.insert(h); if (sync) - continueSync(); + continueSync(_peer); } DEV_INVARIANT_CHECK; } @@ -623,6 +637,7 @@ void EthereumHost::onPeerAborting(EthereumPeer* _peer) _peer->setRude(); continueSync(); } + DEV_INVARIANT_CHECK; } void EthereumHost::continueSync() @@ -811,6 +826,5 @@ bool EthereumHost::invariants() const return false; if (needBlocks() && (m_syncingLatestHash || !m_hashes.empty())) return false; - return true; } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 7a30f1ad9..583932d48 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -100,6 +100,7 @@ void EthereumPeer::requestStatus() { assert(m_asking == Asking::Nothing); setAsking(Asking::State); + m_requireTransactions = true; RLPStream s; bool latest = m_peerCapabilityVersion == host()->protocolVersion(); prep(s, StatusPacket, latest ? 6 : 5) From b6ca0d7856818d4ec43e4a1e21fceb8b5d7a5838 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 15 Jun 2015 20:07:11 +0300 Subject: [PATCH 017/103] Coerage Script --- getcoverage.sh | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/getcoverage.sh b/getcoverage.sh index 4c01bad46..446d584e6 100755 --- a/getcoverage.sh +++ b/getcoverage.sh @@ -2,38 +2,44 @@ CPP_ETHEREUM_PATH=$(pwd) -if [ ! -d "$CPP_ETHEREUM_PATH/build/test" ]; then - echo "You need to compile and build ethereum with cmake -DPROFILING option to the build dir!" - exit; +which $CPP_ETHEREUM_PATH/build/test/testeth >/dev/null 2>&1 +if [ $? != 0 ] +then + echo "You need to compile and build ethereum with cmake -DPROFILING option to the build dir!" + exit; fi OUTPUT_DIR="$CPP_ETHEREUM_PATH/build/test/coverage" TESTETH=$CPP_ETHEREUM_PATH/build #/test/CMakeFiles/testeth.dir if which lcov >/dev/null; then - if which genhtml >/dev/null; then + if which genhtml >/dev/null; then lcov --directory $TESTETH --zerocounters echo Running testeth... - $($CPP_ETHEREUM_PATH/build/test/testeth) + $($CPP_ETHEREUM_PATH/build/test/testeth --all) + $($CPP_ETHEREUM_PATH/build/test/testeth -t StateTests --jit --all) + $($CPP_ETHEREUM_PATH/build/test/testeth -t VMTests --jit --all) echo Prepearing coverage info... - else + else echo genhtml not found exit; - fi + fi else - echo lcov not found - exit; + echo lcov not found + exit; +fi + +if [ -d "$OUTPUT_DIR" ]; then + echo Cleaning previous report... + rm -r $OUTPUT_DIR fi -echo Cleaning previous report... -rm -r $OUTPUT_DIR/testeth -rm $OUTPUT_DIR/full_coverage.info -rm $OUTPUT_DIR/testeth_coverage.info +mkdir $OUTPUT_DIR lcov --capture --directory $TESTETH --output-file $OUTPUT_DIR/full_coverage.info lcov --extract $OUTPUT_DIR/full_coverage.info *cpp-ethereum/* --output-file $OUTPUT_DIR/testeth_coverage.info genhtml $OUTPUT_DIR/testeth_coverage.info --output-directory $OUTPUT_DIR/testeth -echo "Coverage info should be located at: $CPP_ETHEREUM_PATH/build/test/coverage/testeth" +echo "Coverage info should be located at: $OUTPUT_DIR/testeth" echo "Opening index..." -xdg-open $CPP_ETHEREUM_PATH/build/test/coverage/testeth/index.html & +xdg-open $OUTPUT_DIR/testeth/index.html & From be45d62b6144c5ee8f0061bb5e0065ca93cbf33e Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 15 Jun 2015 21:08:22 +0300 Subject: [PATCH 018/103] Code Coverage: bash syntax --- getcoverage.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/getcoverage.sh b/getcoverage.sh index 446d584e6..ac50bf94b 100755 --- a/getcoverage.sh +++ b/getcoverage.sh @@ -16,9 +16,9 @@ if which lcov >/dev/null; then if which genhtml >/dev/null; then lcov --directory $TESTETH --zerocounters echo Running testeth... - $($CPP_ETHEREUM_PATH/build/test/testeth --all) - $($CPP_ETHEREUM_PATH/build/test/testeth -t StateTests --jit --all) - $($CPP_ETHEREUM_PATH/build/test/testeth -t VMTests --jit --all) + $CPP_ETHEREUM_PATH/build/test/testeth -t --all + $CPP_ETHEREUM_PATH/build/test/testeth -t StateTests --jit --all + $CPP_ETHEREUM_PATH/build/test/testeth -t VMTests --jit --all echo Prepearing coverage info... else echo genhtml not found From 2c37204a69d8d73c5f561d327f2781264fafe9ab Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 11 Jun 2015 17:35:50 +0200 Subject: [PATCH 019/103] KeyManager refactoring to increase readability. --- alethzero/MainWin.cpp | 46 ++++--- alethzero/MainWin.h | 2 +- alethzero/OurWebThreeStubServer.cpp | 2 +- alethzero/Transact.cpp | 7 +- eth/main.cpp | 8 +- ethkey/KeyAux.h | 8 +- libdevcore/CommonData.h | 9 +- libethcore/KeyManager.cpp | 169 +++++++++++++++----------- libethcore/KeyManager.h | 66 ++++++---- libweb3jsonrpc/AccountHolder.cpp | 2 +- libweb3jsonrpc/AccountHolder.h | 1 - libweb3jsonrpc/WebThreeStubServer.cpp | 12 +- 12 files changed, 194 insertions(+), 138 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 848020cbc..297ad0eda 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -235,7 +235,7 @@ Main::Main(QWidget *parent) : // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // QWebEngineInspector* inspector = new QWebEngineInspector(); // inspector->setPage(page); - setBeneficiary(*m_keyManager.accounts().begin()); + setBeneficiary(m_keyManager.accounts().front()); ethereum()->setDefault(LatestBlock); @@ -430,9 +430,9 @@ void Main::installBalancesWatch() // TODO: Update for new currencies reg. for (unsigned i = 0; i < ethereum()->stateAt(coinsAddr, PendingBlock); ++i) altCoins.push_back(right160(ethereum()->stateAt(coinsAddr, i + 1))); - for (auto const& i: m_keyManager.accounts()) + for (auto const& address: m_keyManager.accounts()) for (auto c: altCoins) - tf.address(c).topic(0, h256(i, h256::AlignRight)); + tf.address(c).topic(0, h256(address, h256::AlignRight)); uninstallWatch(m_balancesFilter); m_balancesFilter = installWatch(tf, [=](LocalisedLogEntries const&){ onBalancesChange(); }); @@ -501,7 +501,7 @@ void Main::load(QString _s) void Main::on_newTransaction_triggered() { - m_transact->setEnvironment(m_keyManager.accounts(), ethereum(), &m_natSpecDB); + m_transact->setEnvironment(m_keyManager.accountsHash(), ethereum(), &m_natSpecDB); m_transact->show(); } @@ -735,18 +735,17 @@ void Main::writeSettings() s.setValue("windowState", saveState()); } -Secret Main::retrieveSecret(Address const& _a) const +Secret Main::retrieveSecret(Address const& _address) const { - auto info = m_keyManager.accountDetails()[_a]; while (true) { - Secret s = m_keyManager.secret(_a, [&](){ + Secret s = m_keyManager.secret(_address, [&](){ QDialog d; Ui_GetPassword gp; gp.setupUi(&d); d.setWindowTitle("Unlock Account"); - gp.label->setText(QString("Enter the password for the account %2 (%1).").arg(QString::fromStdString(_a.abridged())).arg(QString::fromStdString(info.first))); - gp.entry->setPlaceholderText("Hint: " + QString::fromStdString(info.second)); + gp.label->setText(QString("Enter the password for the account %2 (%1).").arg(QString::fromStdString(_address.abridged())).arg(QString::fromStdString(m_keyManager.accountName(_address)))); + gp.entry->setPlaceholderText("Hint: " + QString::fromStdString(m_keyManager.passwordHint(_address))); return d.exec() == QDialog::Accepted ? gp.entry->text().toStdString() : string(); }); if (s || QMessageBox::warning(nullptr, "Unlock Account", "The password you gave is incorrect for this key.", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) @@ -770,7 +769,7 @@ void Main::readSettings(bool _skipGeometry) for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i) { memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret)); - if (!m_keyManager.accounts().count(KeyPair(k).address())) + if (!m_keyManager.hasAccount(KeyPair(k).address())) m_keyManager.import(k, "Imported (UNSAFE) key."); } } @@ -858,7 +857,7 @@ void Main::on_importKey_triggered() if (b.size() == 32) { auto k = KeyPair(h256(b)); - if (!m_keyManager.accounts().count(k.address())) + if (!m_keyManager.hasAccount(k.address())) { QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name"); if (QMessageBox::question(this, "Additional Security?", "Would you like to use additional security for this key? This lets you protect it with a different password to other keys, but also means you must re-enter the key's password every time you wish to use the account.", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) @@ -939,7 +938,7 @@ void Main::on_claimPresale_triggered() } cnote << k.address(); - if (!m_keyManager.accounts().count(k.address())) + if (!m_keyManager.hasAccount(k.address())) ethereum()->submitTransaction(k.sec(), ethereum()->balanceAt(k.address()) - gasPrice() * c_txGas, m_beneficiary, {}, c_txGas, gasPrice()); else QMessageBox::warning(this, "Already Have Key", "Could not import the secret key: we already own this account."); @@ -1110,13 +1109,13 @@ void Main::refreshBalances() // cdebug << n << addr << denom << sha3(h256(n).asBytes()); altCoins[addr] = make_tuple(fromRaw(n), 0, denom); }*/ - for (pair> const& i: m_keyManager.accountDetails()) + for (auto const& address: m_keyManager.accounts()) { - u256 b = ethereum()->balanceAt(i.first); - QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(i.first))).arg((unsigned)ethereum()->countAt(i.first)).arg(QString::fromStdString(i.second.first)), ui->ourAccounts); - li->setData(Qt::UserRole, QByteArray((char const*)i.first.data(), Address::size)); + u256 b = ethereum()->balanceAt(address); + QListWidgetItem* li = new QListWidgetItem(QString("%4 %2: %1 [%3]").arg(formatBalance(b).c_str()).arg(QString::fromStdString(render(address))).arg((unsigned)ethereum()->countAt(address)).arg(QString::fromStdString(m_keyManager.accountName(address))), ui->ourAccounts); + li->setData(Qt::UserRole, QByteArray((char const*)address.data(), Address::size)); li->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); - li->setCheckState(m_beneficiary == i.first ? Qt::Checked : Qt::Unchecked); + li->setCheckState(m_beneficiary == address ? Qt::Checked : Qt::Unchecked); totalBalance += b; // for (auto& c: altCoins) @@ -2094,9 +2093,8 @@ void Main::on_killAccount_triggered() { auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray(); Address h((byte const*)hba.data(), Address::ConstructFromPointer); - auto k = m_keyManager.accountDetails()[h]; - QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + k.first + "?!"), - QString::fromStdString("Account " + k.first + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it.\r\nIt, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n" + QString s = QInputDialog::getText(this, QString::fromStdString("Kill Account " + m_keyManager.accountName(h) + "?!"), + QString::fromStdString("Account " + m_keyManager.accountName(h) + " (" + render(h) + ") has " + formatBalance(ethereum()->balanceAt(h)) + " in it.\r\nIt, and any contract that this account can access, will be lost forever if you continue. Do NOT continue unless you know what you are doing.\n" "Are you sure you want to continue? \r\n If so, type 'YES' to confirm."), QLineEdit::Normal, "NO"); if (s != "YES") @@ -2104,10 +2102,10 @@ void Main::on_killAccount_triggered() m_keyManager.kill(h); if (m_keyManager.accounts().empty()) m_keyManager.import(Secret::random(), "Default account"); - m_beneficiary = *m_keyManager.accounts().begin(); + m_beneficiary = m_keyManager.accounts().front(); keysChanged(); if (m_beneficiary == h) - setBeneficiary(*m_keyManager.accounts().begin()); + setBeneficiary(m_keyManager.accounts().front()); } } @@ -2128,7 +2126,7 @@ void Main::on_reencryptKey_triggered() return; try { auto pw = [&](){ - auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.hint(a)), QLineEdit::Password, QString()).toStdString(); + auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.passwordHint(a)), QLineEdit::Password, QString()).toStdString(); if (p.empty()) throw PasswordUnknown(); return p; @@ -2151,7 +2149,7 @@ void Main::on_reencryptAll_triggered() try { for (Address const& a: m_keyManager.accounts()) while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){ - auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.hint(a))), QLineEdit::Password, QString()).toStdString(); + auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.passwordHint(a))), QLineEdit::Password, QString()).toStdString(); if (p.empty()) throw PasswordUnknown(); return p; diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index efff89d2b..f8a6fa6c7 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -96,7 +96,7 @@ public: dev::eth::KeyManager& keyManager() override { return m_keyManager; } bool doConfirm(); - dev::Secret retrieveSecret(dev::Address const& _a) const override; + dev::Secret retrieveSecret(dev::Address const& _address) const override; public slots: void load(QString _file); diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index e18cb55d5..aaeffa16b 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -136,7 +136,7 @@ void OurAccountHolder::doValidations() AddressHash OurAccountHolder::realAccounts() const { - return m_main->keyManager().accounts(); + return m_main->keyManager().accountsHash(); } bool OurAccountHolder::validateTransaction(TransactionSkeleton const& _t, bool _toProxy) diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index fd466e475..7a26f56f2 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -77,11 +77,10 @@ void Transact::setEnvironment(AddressHash const& _accounts, dev::eth::Client* _e auto old = ui->from->currentIndex(); ui->from->clear(); - for (auto const& i: m_accounts) + for (auto const& address: m_accounts) { - auto d = m_context->keyManager().accountDetails()[i]; - u256 b = ethereum()->balanceAt(i, PendingBlock); - QString s = QString("%4 %2: %1").arg(formatBalance(b).c_str()).arg(QString::fromStdString(m_context->render(i))).arg(QString::fromStdString(d.first)); + u256 b = ethereum()->balanceAt(address, PendingBlock); + QString s = QString("%4 %2: %1").arg(formatBalance(b).c_str()).arg(QString::fromStdString(m_context->render(address))).arg(QString::fromStdString(m_context->keyManager().accountName(address))); ui->from->addItem(s); } if (old > -1 && old < ui->from->count()) diff --git a/eth/main.cpp b/eth/main.cpp index 382858ae7..a7d9d7c00 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -678,7 +678,7 @@ int main(int argc, char** argv) return ret; }; auto getAccountPassword = [&](Address const& a){ - return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): "); + return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): "); }; StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat, structuredLoggingURL); @@ -1122,10 +1122,10 @@ int main(int argc, char** argv) { cout << "Accounts:" << endl; u256 total = 0; - for (auto const& i: keyManager.accountDetails()) + for (auto const& address: keyManager.accounts()) { - auto b = c->balanceAt(i.first); - cout << ((i.first == signingKey) ? "SIGNING " : " ") << ((i.first == beneficiary) ? "COINBASE " : " ") << i.second.first << " (" << i.first << "): " << formatBalance(b) << " = " << b << " wei" << endl; + auto b = c->balanceAt(address); + cout << ((address == signingKey) ? "SIGNING " : " ") << ((address == beneficiary) ? "COINBASE " : " ") << keyManager.accountName(address) << " (" << address << "): " << formatBalance(b) << " = " << b << " wei" << endl; total += b; } cout << "Total: " << formatBalance(total) << " = " << total << " wei" << endl; diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index d2ec13b2a..b7b10ce21 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -44,7 +44,7 @@ class BadArgument: public Exception {}; string getAccountPassword(KeyManager& keyManager, Address const& a) { - return getPassword("Enter password for address " + keyManager.accountDetails()[a].first + " (" + a.abridged() + "; hint:" + keyManager.accountDetails()[a].second + "): "); + return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): "); } string createPassword(std::string const& _prompt) @@ -359,20 +359,18 @@ public: nonIcap.push_back(u); else { - std::pair info = wallet.accountDetails()[a]; cout << toUUID(u) << " " << a.abridged(); cout << " " << ICAP(a).encoded(); - cout << " " << info.first << endl; + cout << " " << wallet.accountName(a) << endl; } else bare.push_back(u); for (auto const& u: nonIcap) if (Address a = wallet.address(u)) { - std::pair info = wallet.accountDetails()[a]; cout << toUUID(u) << " " << a.abridged(); cout << " (Not ICAP) "; - cout << " " << info.first << endl; + cout << " " << wallet.accountName(a) << endl; } for (auto const& u: bare) cout << toUUID(u) << " (Bare)" << endl; diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index ddc00e09f..780e8f6f5 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -258,7 +259,7 @@ template std::set& operator+=(std::set& _a, U const& _b return _a; } -/// Insert the contents of a container into an unordered_st +/// Insert the contents of a container into an unordered_set template std::unordered_set& operator+=(std::unordered_set& _a, U const& _b) { for (auto const& i: _b) @@ -280,6 +281,12 @@ template std::set operator+(std::set _a, U const& _b) return _a += _b; } +/// Insert the contents of a container into an unordered_set +template std::unordered_set operator+(std::unordered_set _a, U const& _b) +{ + return _a += _b; +} + /// Concatenate the contents of a container onto a vector template std::vector operator+(std::vector _a, U const& _b) { diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp index 4430a588e..602c60b4a 100644 --- a/libethcore/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -31,7 +31,7 @@ using namespace dev; using namespace eth; namespace fs = boost::filesystem; -KeyManager::KeyManager(std::string const& _keysFile, std::string const& _secretsPath): +KeyManager::KeyManager(string const& _keysFile, string const& _secretsPath): m_keysFile(_keysFile), m_store(_secretsPath) {} @@ -43,13 +43,13 @@ bool KeyManager::exists() const return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty(); } -void KeyManager::create(std::string const& _pass) +void KeyManager::create(string const& _pass) { - m_password = asString(h256::random().asBytes()); + m_defaultPasswordDeprecated = asString(h256::random().asBytes()); write(_pass, m_keysFile); } -bool KeyManager::recode(Address const& _address, std::string const& _newPass, std::string const& _hint, std::function const& _pass, KDF _kdf) +bool KeyManager::recode(Address const& _address, string const& _newPass, string const& _hint, function const& _pass, KDF _kdf) { noteHint(_newPass, _hint); h128 u = uuid(_address); @@ -61,10 +61,10 @@ bool KeyManager::recode(Address const& _address, std::string const& _newPass, st return true; } -bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std::function const& _pass, KDF _kdf) +bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, function const& _pass, KDF _kdf) { h128 u = uuid(_address); - std::string p; + string p; if (_newPass == SemanticPassword::Existing) p = getPassword(u, _pass); else if (_newPass == SemanticPassword::Master) @@ -75,41 +75,47 @@ bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std: return recode(_address, p, string(), _pass, _kdf); } -bool KeyManager::load(std::string const& _pass) +bool KeyManager::load(string const& _pass) { - try { + try + { bytes salt = contents(m_keysFile + ".salt"); bytes encKeys = contents(m_keysFile); - m_key = h128(pbkdf2(_pass, salt, 262144, 16)); - bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys); + m_keysFileKey = h128(pbkdf2(_pass, salt, 262144, 16)); + bytes bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys); RLP s(bs); - unsigned version = (unsigned)s[0]; + unsigned version = unsigned(s[0]); if (version == 1) { for (auto const& i: s[1]) { - m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo((h256)i[2], (std::string)i[3]); -// cdebug << toString((Address)i[0]) << toString((h128)i[1]) << toString((h256)i[2]) << (std::string)i[3]; + h128 uuid(i[1]); + Address addr(i[0]); + m_addrLookup[addr] = uuid; + m_keyInfo[uuid] = KeyInfo(h256(i[2]), string(i[3])); +// cdebug << toString(addr) << toString(uuid) << toString((h256)i[2]) << (string)i[3]; } for (auto const& i: s[2]) - m_passwordInfo[(h256)i[0]] = (std::string)i[1]; - m_password = (string)s[3]; + m_passwordHint[h256(i[0])] = string(i[1]); + m_defaultPasswordDeprecated = string(s[3]); } // cdebug << hashPassword(m_password) << toHex(m_password); - m_cachedPasswords[hashPassword(m_password)] = m_password; + cachePassword(m_defaultPasswordDeprecated); // cdebug << hashPassword(asString(m_key.ref())) << m_key.hex(); - m_cachedPasswords[hashPassword(asString(m_key.ref()))] = asString(m_key.ref()); + cachePassword(asString(m_keysFileKey.ref())); // cdebug << hashPassword(_pass) << _pass; - m_cachedPasswords[m_master = hashPassword(_pass)] = _pass; + m_master = hashPassword(_pass); + cachePassword(_pass); return true; } - catch (...) { + catch (...) + { return false; } } -Secret KeyManager::secret(Address const& _address, function const& _pass) const +Secret KeyManager::secret(Address const& _address, function const& _pass) const { auto it = m_addrLookup.find(_address); if (it == m_addrLookup.end()) @@ -117,12 +123,12 @@ Secret KeyManager::secret(Address const& _address, function const return secret(it->second, _pass); } -Secret KeyManager::secret(h128 const& _uuid, function const& _pass) const +Secret KeyManager::secret(h128 const& _uuid, function const& _pass) const { return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); })); } -std::string KeyManager::getPassword(h128 const& _uuid, function const& _pass) const +string KeyManager::getPassword(h128 const& _uuid, function const& _pass) const { auto kit = m_keyInfo.find(_uuid); h256 ph; @@ -131,19 +137,19 @@ std::string KeyManager::getPassword(h128 const& _uuid, function c return getPassword(ph, _pass); } -std::string KeyManager::getPassword(h256 const& _passHash, function const& _pass) const +string KeyManager::getPassword(h256 const& _passHash, function const& _pass) const { auto it = m_cachedPasswords.find(_passHash); if (it != m_cachedPasswords.end()) return it->second; - for (unsigned i = 0; i< 10; ++i) + for (unsigned i = 0; i < 10; ++i) { - std::string p = _pass(); + string p = _pass(); if (p.empty()) break; - if (hashPassword(p) == _passHash || _passHash == UnknownPassword) + if (_passHash == UnknownPassword || hashPassword(p) == _passHash) { - m_cachedPasswords[hashPassword(p)] = p; + cachePassword(p); return p; } } @@ -166,20 +172,20 @@ Address KeyManager::address(h128 const& _uuid) const return Address(); } -h128 KeyManager::import(Secret const& _s, string const& _info, std::string const& _pass, string const& _passInfo) +h128 KeyManager::import(Secret const& _s, string const& _accountName, string const& _pass, string const& _passwordHint) { Address addr = KeyPair(_s).address(); auto passHash = hashPassword(_pass); - m_cachedPasswords[passHash] = _pass; - m_passwordInfo[passHash] = _passInfo; + cachePassword(_pass); + m_passwordHint[passHash] = _passwordHint; auto uuid = m_store.importSecret(_s.asBytes(), _pass); - m_keyInfo[uuid] = KeyInfo{passHash, _info}; + m_keyInfo[uuid] = KeyInfo{passHash, _accountName}; m_addrLookup[addr] = uuid; write(m_keysFile); return uuid; } -void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo) +void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint) { bytes key = m_store.secret(_uuid, [&](){ return _pass; }); if (key.empty()) @@ -187,17 +193,17 @@ void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, std Address a = KeyPair(Secret(key)).address(); auto passHash = hashPassword(_pass); if (!m_cachedPasswords.count(passHash)) - m_cachedPasswords[passHash] = _pass; - importExisting(_uuid, _info, a, passHash, _passInfo); + cachePassword(_pass); + importExisting(_uuid, _info, a, passHash, _passwordHint); } -void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, Address const& _address, h256 const& _passHash, std::string const& _passInfo) +void KeyManager::importExisting(h128 const& _uuid, string const& _accountName, Address const& _address, h256 const& _passHash, string const& _passwordHint) { - if (!m_passwordInfo.count(_passHash)) - m_passwordInfo[_passHash] = _passInfo; + if (!m_passwordHint.count(_passHash)) + m_passwordHint[_passHash] = _passwordHint; m_addrLookup[_address] = _uuid; m_keyInfo[_uuid].passHash = _passHash; - m_keyInfo[_uuid].info = _info; + m_keyInfo[_uuid].accountName = _accountName; write(m_keysFile); } @@ -209,67 +215,92 @@ void KeyManager::kill(Address const& _a) m_store.kill(id); } -AddressHash KeyManager::accounts() const +Addresses KeyManager::accounts() const { - AddressHash ret; + Addresses ret; + ret.reserve(m_addrLookup.size()); for (auto const& i: m_addrLookup) if (m_keyInfo.count(i.second) > 0) - ret.insert(i.first); + ret.push_back(i.first); return ret; } -std::unordered_map> KeyManager::accountDetails() const +bool KeyManager::hasAccount(const Address& _address) const { - std::unordered_map> ret; - for (auto const& i: m_addrLookup) - if (m_keyInfo.count(i.second) > 0) - ret[i.first] = make_pair(m_keyInfo.count(i.second) ? m_keyInfo.at(i.second).info : "", m_keyInfo.count(i.second) && m_passwordInfo.count(m_keyInfo.at(i.second).passHash) ? m_passwordInfo.at(m_keyInfo.at(i.second).passHash) : ""); - return ret; + return m_addrLookup.count(_address) && m_keyInfo.count(m_addrLookup.at(_address)); +} + +string const& KeyManager::accountName(Address const& _address) const +{ + try + { + return m_keyInfo.at(m_addrLookup.at(_address)).accountName; + } + catch (...) + { + return EmptyString; + } +} + +string const& KeyManager::passwordHint(Address const& _address) const +{ + try + { + return m_passwordHint.at(m_keyInfo.at(m_addrLookup.at(_address)).passHash); + } + catch (...) + { + return EmptyString; + } } -h256 KeyManager::hashPassword(std::string const& _pass) const +h256 KeyManager::hashPassword(string const& _pass) const { // TODO SECURITY: store this a bit more securely; Scrypt perhaps? - return h256(pbkdf2(_pass, asBytes(m_password), 262144, 32)); + return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32)); +} + +void KeyManager::cachePassword(string const& _password) const +{ + m_cachedPasswords[hashPassword(_password)] = _password; } -bool KeyManager::write(std::string const& _keysFile) const +bool KeyManager::write(string const& _keysFile) const { - if (!m_key) + if (!m_keysFileKey) return false; - write(m_key, _keysFile); + write(m_keysFileKey, _keysFile); return true; } -void KeyManager::write(std::string const& _pass, std::string const& _keysFile) const +void KeyManager::write(string const& _pass, string const& _keysFile) const { bytes salt = h256::random().asBytes(); writeFile(_keysFile + ".salt", salt); auto key = h128(pbkdf2(_pass, salt, 262144, 16)); - m_cachedPasswords[hashPassword(_pass)] = _pass; + cachePassword(_pass); m_master = hashPassword(_pass); write(key, _keysFile); } -void KeyManager::write(h128 const& _key, std::string const& _keysFile) const +void KeyManager::write(h128 const& _key, string const& _keysFile) const { RLPStream s(4); - s << 1; - s.appendList(m_addrLookup.size()); - for (auto const& i: m_addrLookup) - if (m_keyInfo.count(i.second)) - { - auto ki = m_keyInfo.at(i.second); - s.appendList(4) << i.first << i.second << ki.passHash << ki.info; - } - s.appendList(m_passwordInfo.size()); - for (auto const& i: m_passwordInfo) + s << 1; // version + s.appendList(accounts().size()); + for (auto const& address: accounts()) + { + h128 id = uuid(address); + auto const& ki = m_keyInfo.at(id); + s.appendList(4) << address << id << ki.passHash << ki.accountName; + } + s.appendList(m_passwordHint.size()); + for (auto const& i: m_passwordHint) s.appendList(2) << i.first << i.second; - s.append(m_password); + s.append(m_defaultPasswordDeprecated); writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out())); - m_key = _key; - m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword(); - + m_keysFileKey = _key; + cachePassword(defaultPassword()); } diff --git a/libethcore/KeyManager.h b/libethcore/KeyManager.h index 62263c3c5..d9bb6457c 100644 --- a/libethcore/KeyManager.h +++ b/libethcore/KeyManager.h @@ -23,8 +23,9 @@ #include #include -#include #include +#include +#include namespace dev { @@ -35,14 +36,15 @@ class PasswordUnknown: public Exception {}; struct KeyInfo { KeyInfo() = default; - KeyInfo(h256 const& _passHash, std::string const& _info): passHash(_passHash), info(_info) {} + KeyInfo(h256 const& _passHash, std::string const& _accountName): passHash(_passHash), accountName(_accountName) {} - h256 passHash; ///< Hash of the password or h256() if unknown. - std::string info; ///< Name of the key, or JSON key info if begins with '{'. + h256 passHash; ///< Hash of the password or h256() / UnknownPassword if unknown. + std::string accountName; ///< Name of the key, or JSON key info if begins with '{'. }; -static const h256 UnknownPassword; -static const auto DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); }; +static h256 const UnknownPassword; +/// Password query function that never returns a password. +static auto const DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); }; enum class SemanticPassword { @@ -53,12 +55,15 @@ enum class SemanticPassword // TODO: This one is specifically for Ethereum, but we can make it generic in due course. // TODO: hidden-partition style key-store. /** - * @brief High-level manager of keys for Ethereum. + * @brief High-level manager of password-encrypted keys for Ethereum. * Usage: * * Call exists() to check whether there is already a database. If so, get the master password from * the user and call load() with it. If not, get a new master password from the user (get them to type * it twice and keep some hint around!) and call create() with it. + * + * Uses a "key file" (and a corresponding .salt file) that contains encrypted information about the keys and + * a directory called "secrets path" that contains a file for each key. */ class KeyManager { @@ -75,25 +80,37 @@ public: void save(std::string const& _pass) const { write(_pass, m_keysFile); } void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; } - void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordInfo[hashPassword(_pass)] = _hint; } + void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordHint[hashPassword(_pass)] = _hint; } bool haveHint(std::string const& _pass) const { auto h = hashPassword(_pass); return m_cachedPasswords.count(h) && !m_cachedPasswords.at(h).empty(); } - AddressHash accounts() const; - std::unordered_map> accountDetails() const; - std::string const& hint(Address const& _a) const { try { return m_passwordInfo.at(m_keyInfo.at(m_addrLookup.at(_a)).passHash); } catch (...) { return EmptyString; } } - + /// @returns the list of account addresses. + Addresses accounts() const; + /// @returns a hashset of all account addresses. + AddressHash accountsHash() const { return AddressHash() + accounts(); } + bool hasAccount(Address const& _address) const; + /// @returns the human-readable name or json-encoded info of the account for the given address. + std::string const& accountName(Address const& _address) const; + /// @returns the password hint for the account for the given address; + std::string const& passwordHint(Address const& _address) const; + + /// @returns the uuid of the key for the address @a _a or the empty hash on error. h128 uuid(Address const& _a) const; + /// @returns the address corresponding to the key with uuid @a _uuid or the zero address on error. Address address(h128 const& _uuid) const; - h128 import(Secret const& _s, std::string const& _info, std::string const& _pass, std::string const& _passInfo); - h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, defaultPassword(), std::string()); } + h128 import(Secret const& _s, std::string const& _accountName, std::string const& _pass, std::string const& _passwordHint); + h128 import(Secret const& _s, std::string const& _accountName) { return import(_s, _accountName, defaultPassword(), std::string()); } SecretStore& store() { return m_store; } - void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo); - void importExisting(h128 const& _uuid, std::string const& _info) { importExisting(_uuid, _info, defaultPassword(), std::string()); } - void importExisting(h128 const& _uuid, std::string const& _info, Address const& _addr, h256 const& _passHash = h256(), std::string const& _passInfo = std::string()); + void importExisting(h128 const& _uuid, std::string const& _accountName, std::string const& _pass, std::string const& _passwordHint); + void importExisting(h128 const& _uuid, std::string const& _accountName) { importExisting(_uuid, _accountName, defaultPassword(), std::string()); } + void importExisting(h128 const& _uuid, std::string const& _accountName, Address const& _addr, h256 const& _passHash = h256(), std::string const& _passwordHint = std::string()); + /// @returns the secret key associated with an address provided the password query + /// function @a _pass or the zero-secret key on error. Secret secret(Address const& _address, std::function const& _pass = DontKnowThrow) const; + /// @returns the secret key associated with the uuid of a key provided the password query + /// function @a _pass or the zero-secret key on error. Secret secret(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; bool recode(Address const& _address, SemanticPassword _newPass, std::function const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt); @@ -110,6 +127,9 @@ private: std::string defaultPassword(std::function const& _pass = DontKnowThrow) const { return getPassword(m_master, _pass); } h256 hashPassword(std::string const& _pass) const; + /// Stores the password by its hash in the password cache. + void cachePassword(std::string const& _password) const; + // Only use if previously loaded ok. // @returns false if wasn't previously loaded ok. bool write() const { return write(m_keysFile); } @@ -118,11 +138,15 @@ private: void write(h128 const& _key, std::string const& _keysFile) const; // Ethereum keys. + + /// Mapping address -> key uuid. std::unordered_map m_addrLookup; + /// Mapping key uuid -> key info. std::unordered_map m_keyInfo; - std::unordered_map m_passwordInfo; + /// Mapping password hash -> password hint. + std::unordered_map m_passwordHint; - // Passwords that we're storing. + // Passwords that we're storing. Mapping password hash -> password. mutable std::unordered_map m_cachedPasswords; // DEPRECATED. @@ -130,10 +154,10 @@ private: // Now the default password is based off the key of the keys file directly, so this is redundant // except for the fact that people have existing keys stored with it. Leave for now until/unless // we have an upgrade strategy. - std::string m_password; + std::string m_defaultPasswordDeprecated; mutable std::string m_keysFile; - mutable h128 m_key; + mutable h128 m_keysFileKey; mutable h256 m_master; SecretStore m_store; }; diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp index abd0a1adf..3250eae6b 100644 --- a/libweb3jsonrpc/AccountHolder.cpp +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -103,7 +103,7 @@ void AccountHolder::clearQueue(int _id) AddressHash SimpleAccountHolder::realAccounts() const { - return m_keyManager.accounts(); + return m_keyManager.accountsHash(); } void SimpleAccountHolder::authenticate(dev::eth::TransactionSkeleton const& _t) diff --git a/libweb3jsonrpc/AccountHolder.h b/libweb3jsonrpc/AccountHolder.h index 10b036226..559f8509a 100644 --- a/libweb3jsonrpc/AccountHolder.h +++ b/libweb3jsonrpc/AccountHolder.h @@ -48,7 +48,6 @@ class AccountHolder public: explicit AccountHolder(std::function const& _client): m_client(_client) {} - // easiest to return keyManager.addresses(); virtual AddressHash realAccounts() const = 0; // use m_web3's submitTransaction // or use AccountHolder::queueTransaction(_t) to accept diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index adef51033..f0e532c5c 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -157,19 +157,19 @@ Json::Value WebThreeStubServer::admin_eth_allAccounts(std::string const& _sessio u256 total = 0; u256 pendingtotal = 0; Address beneficiary; - for (auto const& i: m_keyMan.accountDetails()) + for (auto const& address: m_keyMan.accounts()) { - auto pending = m_web3.ethereum()->balanceAt(i.first, PendingBlock); - auto latest = m_web3.ethereum()->balanceAt(i.first, LatestBlock); + auto pending = m_web3.ethereum()->balanceAt(address, PendingBlock); + auto latest = m_web3.ethereum()->balanceAt(address, LatestBlock); Json::Value a; - if (i.first == beneficiary) + if (address == beneficiary) a["beneficiary"] = true; - a["address"] = toJS(i.first); + a["address"] = toJS(address); a["balance"] = toJS(latest); a["nicebalance"] = formatBalance(latest); a["pending"] = toJS(pending); a["nicepending"] = formatBalance(pending); - ret["accounts"][i.second.first] = a; + ret["accounts"][m_keyMan.accountName(address)] = a; total += latest; pendingtotal += pending; } From b381bc6f489b76b9986161f14fea0948a67b8769 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 16 Jun 2015 01:26:11 +0300 Subject: [PATCH 020/103] Script Coverage --- getcoverage.sh | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/getcoverage.sh b/getcoverage.sh index ac50bf94b..8d34d733c 100755 --- a/getcoverage.sh +++ b/getcoverage.sh @@ -10,35 +10,37 @@ then fi OUTPUT_DIR="$CPP_ETHEREUM_PATH/build/test/coverage" -TESTETH=$CPP_ETHEREUM_PATH/build #/test/CMakeFiles/testeth.dir +TESTETH=$CPP_ETHEREUM_PATH/build if which lcov >/dev/null; then if which genhtml >/dev/null; then - lcov --directory $TESTETH --zerocounters - echo Running testeth... - $CPP_ETHEREUM_PATH/build/test/testeth -t --all - $CPP_ETHEREUM_PATH/build/test/testeth -t StateTests --jit --all - $CPP_ETHEREUM_PATH/build/test/testeth -t VMTests --jit --all - echo Prepearing coverage info... + echo Cleaning previous report... + if [ -d "$OUTPUT_DIR" ]; then + rm -r $OUTPUT_DIR + fi + mkdir $OUTPUT_DIR + lcov --directory $TESTETH --zerocounters + lcov --capture --initial --directory $TESTETH --output-file $OUTPUT_DIR/coverage_base.info + + echo Running testeth... + $CPP_ETHEREUM_PATH/build/test/testeth --all + $CPP_ETHEREUM_PATH/build/test/testeth -t StateTests --jit --all + $CPP_ETHEREUM_PATH/build/test/testeth -t VMTests --jit --all + + echo Prepearing coverage info... + lcov --capture --directory $TESTETH --output-file $OUTPUT_DIR/coverage_test.info + lcov --add-tracefile $OUTPUT_DIR/coverage_base.info --add-tracefile $OUTPUT_DIR/coverage_test.info --output-file $OUTPUT_DIR/coverage_all.info + lcov --extract $OUTPUT_DIR/coverage_all.info *cpp-ethereum/* --output-file $OUTPUT_DIR/coverage_export.info + genhtml $OUTPUT_DIR/coverage_export.info --output-directory $OUTPUT_DIR/testeth else - echo genhtml not found - exit; + echo genhtml not found + exit; fi else echo lcov not found exit; fi -if [ -d "$OUTPUT_DIR" ]; then - echo Cleaning previous report... - rm -r $OUTPUT_DIR -fi - -mkdir $OUTPUT_DIR -lcov --capture --directory $TESTETH --output-file $OUTPUT_DIR/full_coverage.info -lcov --extract $OUTPUT_DIR/full_coverage.info *cpp-ethereum/* --output-file $OUTPUT_DIR/testeth_coverage.info -genhtml $OUTPUT_DIR/testeth_coverage.info --output-directory $OUTPUT_DIR/testeth - echo "Coverage info should be located at: $OUTPUT_DIR/testeth" echo "Opening index..." From e23d6f68d7d8f334ddd03852568e9a5b6b71f1ef Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 16 Jun 2015 11:33:57 +0200 Subject: [PATCH 021/103] add ability to have invalid Pow in BlockChaintests --- test/libethereum/blockchain.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 2c4a0b498..50e10bb8a 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -581,6 +581,12 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector } updatePoW(uncleBlockFromFields); + if (overwrite == "nonce" || overwrite == "mixHash") + { + uncleBlockFromFields.nonce = overwrite == "nonce" ? Nonce(uncleHeaderObj["nonce"].get_str()) : uncleBlockFromFields.nonce; + uncleBlockFromFields.mixHash = overwrite == "mixHash" ? h256(uncleHeaderObj["mixHash"].get_str()) : uncleBlockFromFields.mixHash; + } + writeBlockHeaderToJson(uncleHeaderObj, uncleBlockFromFields); aUncleList.push_back(uncleHeaderObj); @@ -677,16 +683,18 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) tmp.timestamp = toInt(ho["timestamp"]); if (ho.count("extraData")) tmp.extraData = importByteArray(ho["extraData"].get_str()); - if (ho.count("mixHash")) - tmp.mixHash = h256(ho["mixHash"].get_str()); - tmp.noteDirty(); // find new valid nonce if (tmp != _header) - { mine(tmp); - _header = tmp; - } + + if (ho.count("mixHash")) + tmp.mixHash = h256(ho["mixHash"].get_str()); + if (ho.count("nonce")) + tmp.nonce = Nonce(ho["nonce"].get_str()); + + tmp.noteDirty(); + _header = tmp; } else { From a6bb3d4302f694a6821743d24b0a480c2556115a Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 16 Jun 2015 11:34:31 +0200 Subject: [PATCH 022/103] add invalid PoW in blockheader tests --- .../bcInvalidHeaderTestFiller.json | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json b/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json index a800f86bf..83e541da1 100644 --- a/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json @@ -176,6 +176,124 @@ ] }, + "wrongMixHash" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "blocks" : [ + { + "blockHeader" : { + "mixHash" : "0xbad81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + + "wrongNonce" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "blocks" : [ + { + "blockHeader" : { + "nonce" : "0x0102030405060708" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + "wrongDifficulty" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", From a3823da2babeb618217d9edc4022c270161953a8 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 16 Jun 2015 11:35:03 +0200 Subject: [PATCH 023/103] add invalid PoW in uncle blockheader tests --- .../bcUncleHeaderValiditiyFiller.json | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/test/libethereum/BlockTestsFiller/bcUncleHeaderValiditiyFiller.json b/test/libethereum/BlockTestsFiller/bcUncleHeaderValiditiyFiller.json index ee36e230d..498486fdf 100644 --- a/test/libethereum/BlockTestsFiller/bcUncleHeaderValiditiyFiller.json +++ b/test/libethereum/BlockTestsFiller/bcUncleHeaderValiditiyFiller.json @@ -418,6 +418,216 @@ ] }, + "wrongMixHash" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "231072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + { + "overwriteAndRedoPoW" : "mixHash", + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "acde5374fce5edbc8e2a8697c15331677e6ebf0b", + "difficulty" : "230847", + "extraData" : "0x", + "gasLimit" : "3141593", + "gasUsed" : "150000", + "hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04", + "mixHash" : "bad7f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770", + "nonce" : "18a524c1790fa83b", + "number" : "2", + "parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd", + "timestamp" : "142813170", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } + ] + } + ] + }, + + "nonceWrong" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "231072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "30" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "3" + }, + "acde5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1312500000000000000" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + { + "overwriteAndRedoPoW" : "nonce", + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "acde5374fce5edbc8e2a8697c15331677e6ebf0b", + "difficulty" : "230847", + "extraData" : "0x", + "gasLimit" : "3141593", + "gasUsed" : "150000", + "hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04", + "mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770", + "nonce" : "bad524c1790fa83b", + "number" : "2", + "parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd", + "timestamp" : "142813170", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } + ] + } + ] + }, + "gasLimitTooHigh" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", From 4bb4a8aa609e952db39cc833963b5958582900b3 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 16 Jun 2015 12:05:15 +0200 Subject: [PATCH 024/103] Add cmake command for OpenCL kernel code The OpenCL kernel gets parsed and copied into a byte array accessible by a specific header during the cmake configuration step. We are now adding a special command "make clbin2h" which would generate this header byte array on demand --- libethash-cl/CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libethash-cl/CMakeLists.txt b/libethash-cl/CMakeLists.txt index fdc2dad07..6533bf794 100644 --- a/libethash-cl/CMakeLists.txt +++ b/libethash-cl/CMakeLists.txt @@ -5,6 +5,16 @@ bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl VARIABLE_NAME ethash_cl_miner_kernel HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) +# Add a custom command so that the user can regenerate the header file containing the kernel +# code's bytearray by running "make clbin2h" + add_custom_target(clbin2h) + add_custom_command(TARGET clbin2h + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -DBIN2H_SOURCE_FILE="${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl" + -DBIN2H_VARIABLE_NAME=ethash_cl_miner_kernel + -DBIN2H_HEADER_FILE="${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h" + -P "${CMAKE_CURRENT_SOURCE_DIR}/bin2h.cmake") + aux_source_directory(. SRC_LIST) file(GLOB HEADERS "*.h") From 9ddf68b7f49b629d06962fbd3489479ac7178b97 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 16 Jun 2015 12:58:52 +0200 Subject: [PATCH 025/103] - array validation in QML - compliant with multi dim/dynamic array --- mix/ContractCallDataEncoder.cpp | 116 +++++++++++++++++++++++--------- mix/ContractCallDataEncoder.h | 5 +- mix/qml/js/InputValidator.js | 113 +++++++++++++++++++++++++++---- 3 files changed, 187 insertions(+), 47 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 07ab8dd73..08e764955 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -20,15 +20,19 @@ * Ethereum IDE client. */ -#include +#include #include #include +#include +#include +#include #include #include #include "QVariableDeclaration.h" #include "QVariableDefinition.h" #include "QFunctionDefinition.h" #include "ContractCallDataEncoder.h" +using namespace std; using namespace dev; using namespace dev::solidity; using namespace dev::mix; @@ -38,13 +42,18 @@ bytes ContractCallDataEncoder::encodedData() bytes r(m_encodedData); size_t headerSize = m_encodedData.size() & ~0x1fUL; //ignore any prefix that is not 32-byte aligned //apply offsets - for (auto const& p: m_offsetMap) + for (auto const& p: m_dynamicOffsetMap) + { + vector_ref offsetRef(m_dynamicData.data() + p.first, 32); + toBigEndian>(p.second + headerSize, offsetRef); //add header size minus signature hash + } + for (auto const& p: m_staticOffsetMap) { vector_ref offsetRef(r.data() + p.first, 32); toBigEndian>(p.second + headerSize, offsetRef); //add header size minus signature hash } - - r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end()); + if (m_dynamicData.size() > 0) + r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end()); return r; } @@ -54,54 +63,95 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end()); } +void ContractCallDataEncoder::encodeArray(QJsonArray const& _array, QList _dim, SolidityType const& _type, bytes& _content) +{ + size_t offsetStart = _content.size(); + if (_dim[0] == -1) + { + bytes count = bytes(32); + toBigEndian((u256)_array.size(), count); + _content += count; //reserved space for count + } + _dim.pop_front(); + + int k = 0; + for (QJsonValue const& c: _array) + { + if (c.isArray()) + { + if (_dim[0] == -1) + { + m_dynamicOffsetMap.push_back(std::make_pair(m_dynamicData.size() + offsetStart + 32 + k * 32, + m_dynamicData.size() + _content.size())); + } + encodeArray(c.toArray(), _dim, _type, _content); + } + else + { + // encode single item + if (c.isDouble()) + encodeSingleItem(QString::number(c.toDouble()), _type, _content); + else if (c.isString()) + encodeSingleItem(c.toString(), _type, _content); + } + k++; + } +} + void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& _type) { - u256 count = 1; QStringList strList; + vector dim; if (_type.array) { - if (_data.type() == QVariant::String) - strList = _data.toString().split(",", QString::SkipEmptyParts); //TODO: proper parsing - else - strList = _data.toStringList(); - count = strList.count(); + QList dim = extractDimension(_type. name); + bytes content; + QJsonDocument jsonResponse = QJsonDocument::fromJson(_data.toString().toUtf8()); + QJsonArray jsonObject = jsonResponse.array(); + size_t size = m_encodedData.size(); + if (dim[0] == -1) + { + m_encodedData += bytes(32); // reserve space for offset + m_staticOffsetMap.push_back(std::make_pair(size, m_dynamicData.size())); + } + encodeArray(jsonObject, dim, _type, content); + if (!_type.dynamicSize) + m_encodedData.insert(m_encodedData.end(), content.begin(), content.end()); + else + m_dynamicData.insert(m_dynamicData.end(), content.begin(), content.end()); } - else - strList.append(_data.toString()); - - if (_type.dynamicSize) + else if (_type.dynamicSize && _type.type == SolidityType::Type::Bytes) { bytes empty(32); size_t sizePos = m_dynamicData.size(); m_dynamicData += empty; //reserve space for count - if (_type.type == SolidityType::Type::Bytes) - count = encodeSingleItem(_data.toString(), _type, m_dynamicData); - else - { - count = strList.count(); - for (auto const& item: strList) - encodeSingleItem(item, _type, m_dynamicData); - } + u256 count = encodeSingleItem(_data.toString(), _type, m_dynamicData); vector_ref sizeRef(m_dynamicData.data() + sizePos, 32); toBigEndian(count, sizeRef); - m_offsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); + m_staticOffsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); m_encodedData += empty; //reserve space for offset } else + encodeSingleItem(_data.toString(), _type, m_encodedData); +} + +QList ContractCallDataEncoder::extractDimension(QString const& _type) +{ + QList dim; + QRegExp dimExtract("(\\[[^\\]]*\\])"); + int pos = dimExtract.indexIn(_type); + while (pos != -1) { - if (_type.array) - count = _type.count; - int c = static_cast(count); - if (strList.size() > c) - strList.erase(strList.begin() + c, strList.end()); + QString d = dimExtract.cap(0); + pos += d.length(); + pos = dimExtract.indexIn(_type, pos); + if (d == "[]") + dim.push_front(-1); else - while (strList.size() < c) - strList.append(QString()); - - for (auto const& item: strList) - encodeSingleItem(item, _type, m_encodedData); + dim.push_front(d.replace("[", "").replace("]", "").toInt()); } + return dim; } unsigned ContractCallDataEncoder::encodeSingleItem(QString const& _data, SolidityType const& _type, bytes& _dest) diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 2707845ae..629e46b0d 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -69,11 +69,14 @@ private: QString toString(bool _b); QString toString(dev::bytes const& _b); bool asString(dev::bytes const& _b, QString& _str); + QList extractDimension(QString const& _type); + void encodeArray(QJsonArray const& _array, QList _dim, SolidityType const& _type, bytes& _content); private: bytes m_encodedData; bytes m_dynamicData; - std::vector> m_offsetMap; + std::vector> m_dynamicOffsetMap; + std::vector> m_staticOffsetMap; }; } diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js index 37185b898..8a8ef1715 100644 --- a/mix/qml/js/InputValidator.js +++ b/mix/qml/js/InputValidator.js @@ -1,27 +1,20 @@ Qt.include("QEtherHelper.js") var nbRegEx = new RegExp('^[0-9]+$'); +var arrayRegEx = new RegExp('\\[[^\\]]*\\]', "g"); +var capturenbRegEx = new RegExp("[0-9]+"); + function validate(model, values) { var inError = []; for (var k in model) { + init() if (values[model[k].name]) { var type = model[k].type.name; - var res; - if (isContractType(type)) - res = validateAddress(type, values[model[k].name]); - else if (type.indexOf("int") !== -1) - res = validateInt(type, values[model[k].name]); - else if (type.indexOf("bytes") !== -1) - res = validateBytes(type, values[model[k].name]); - else if (type.indexOf("bool") !== -1) - res = validateBool(type, values[model[k].name]); - else if (type.indexOf("address") !== -1) - res = validateAddress(type, values[model[k].name]); - else - res.valid = true; + var value = values[model[k].name]; + var res = check(type, value) if (!res.valid) inError.push({ type: type, value: values, message: res.message }); } @@ -29,6 +22,100 @@ function validate(model, values) return inError; } +function init() +{ + nbRegEx = new RegExp('^[0-9]+$'); + arrayRegEx = new RegExp('\\[[^\\]]*\\]', "g"); + capturenbRegEx = new RegExp("[0-9]+"); +} + +function check(type, value) +{ + var res = { valid: true, message : "" } + if (isContractType(type)) + res = validateAddress(type, value); + else if (isArray(type)) + res = validateArray(type, value); + else if (type.indexOf("int") !== -1) + res = validateInt(type, value); + else if (type.indexOf("bytes") !== -1) + res = validateBytes(type, value); + else if (type.indexOf("bool") !== -1) + res = validateBool(type, value); + else if (type.indexOf("address") !== -1) + res = validateAddress(type, value); + else + { + res.valid = true + res.message = "" + } + return res; +} + +function isArray(_type) +{ + if (!arrayRegEx.test(_type)) + return false + else + return (_type.indexOf("int") !== -1 || _type.indexOf("bytes") !== -1 || _type.indexOf("bool") !== -1 || _type.indexOf("adress") !== -1) +} + +function checkArrayRecursively(_type, _dim, _array) +{ + if (_array instanceof Array) + { + if (_dim.length === 0) + return { valid: false, message: "Your input contains too many dimensions" } + var size = -1 + var infinite = false + if (_dim === "[]") + infinite = true + else + size = parseInt(capturenbRegEx.exec(_dim[0])) + if (_array.length > size && !infinite) + return { valid: false, message: "Array size does not correspond. Should be " + _dim[0] } + if (_array.length > 0) + { + var _newdim = _dim.slice(0) + _newdim.splice(0, 1) + for (var i = 0; i < _array.length; i++) + { + var ret = checkArrayRecursively(_type, _newdim, _array[i]) + if (!ret.valid) + return ret + } + } + return { valid: true, message: "" } + } + else + { + if (_dim.length > 0) + return { valid: false, message: "Your input contains too few dimensions" } + if (typeof(_array) === "number") + _array = '' + _array + '' + return check(_type, _array) + } +} + +function validateArray(_type, _value) +{ + try + { + _value = JSON.parse(_value) + } + catch (e) + { + return { valid: false, message: "Input must be JSON formatted like [1,5,3,9] or [[4,9],[4,9],[4,9],[4,9]]" } + } + var dim = _type.match(arrayRegEx) + dim.reverse(); + for (var k = 0; k < dim.length; k++) + { + _type = _type.replace(dim[k], "") + } + return checkArrayRecursively(_type, dim, _value) +} + function isContractType(_type) { for (var k in Object.keys(codeModel.contracts)) From c19fb34c9ab4de7cc43c5f43be5ea141ccf19a09 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 16 Jun 2015 13:29:16 +0200 Subject: [PATCH 026/103] quick_difficulty_check difficulty argument clarification The argument passed into ethash_quick_check_difficulty is not the actual difficulty but it's 2^256 divided by the difficulty. --- internal.c | 4 ++-- internal.h | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/internal.c b/internal.c index b28a59e43..338aa5ecd 100644 --- a/internal.c +++ b/internal.c @@ -284,13 +284,13 @@ bool ethash_quick_check_difficulty( ethash_h256_t const* header_hash, uint64_t const nonce, ethash_h256_t const* mix_hash, - ethash_h256_t const* difficulty + ethash_h256_t const* boundary ) { ethash_h256_t return_hash; ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash); - return ethash_check_difficulty(&return_hash, difficulty); + return ethash_check_difficulty(&return_hash, boundary); } ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed) diff --git a/internal.h b/internal.h index 4e2b695ac..26c395ad6 100644 --- a/internal.h +++ b/internal.h @@ -46,27 +46,36 @@ static inline void ethash_h256_reset(ethash_h256_t* hash) memset(hash, 0, 32); } -// Returns if hash is less than or equal to difficulty +// Returns if hash is less than or equal to boundary (2^256/difficulty) static inline bool ethash_check_difficulty( ethash_h256_t const* hash, - ethash_h256_t const* difficulty + ethash_h256_t const* boundary ) { - // Difficulty is big endian + // Boundary is big endian for (int i = 0; i < 32; i++) { - if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) { + if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) { continue; } - return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i); + return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i); } return true; } +/** + * Difficulty quick check for POW preverification + * + * @param header_hash The hash of the header + * @param nonce The block's nonce + * @param mix_hash The mix digest hash + * @param boundary The boundary is defined as (2^256 / difficulty) + * @return true for succesful pre-verification and false otherwise + */ bool ethash_quick_check_difficulty( ethash_h256_t const* header_hash, uint64_t const nonce, ethash_h256_t const* mix_hash, - ethash_h256_t const* difficulty + ethash_h256_t const* boundary ); struct ethash_light { From e486ce32f16999a842af42627dcec2c076fc1820 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 16 Jun 2015 13:33:36 +0200 Subject: [PATCH 027/103] add diff is zero test --- .../bcInvalidHeaderTestFiller.json | 59 +++++++++++++++++++ test/libethereum/blockchain.cpp | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json b/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json index 83e541da1..3084db0d7 100644 --- a/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json @@ -353,6 +353,65 @@ ] }, + "DifficultyIsZero" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "blocks" : [ + { + "blockHeader" : { + "difficulty" : "0" + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "50000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000" + } + ], + "uncleHeaders" : [ + ] + } + ] + }, + "DifferentExtraData1025" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 50e10bb8a..2dc30c6ba 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -685,7 +685,7 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) tmp.extraData = importByteArray(ho["extraData"].get_str()); // find new valid nonce - if (tmp != _header) + if (tmp != _header && tmp.difficulty) mine(tmp); if (ho.count("mixHash")) From 0ea695c699c21affeca39cf33ae488a120400eda Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 16 Jun 2015 13:41:05 +0200 Subject: [PATCH 028/103] fix for #2194 #2145 --- mix/ContractCallDataEncoder.cpp | 13 +++++++++---- mix/ContractCallDataEncoder.h | 1 + mix/qml/js/ProjectModel.js | 9 ++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 08e764955..bc3322145 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -248,12 +248,15 @@ dev::bytes ContractCallDataEncoder::decodeBytes(dev::bytes const& _rawValue) } QString ContractCallDataEncoder::toString(dev::bytes const& _b) +{ + return QString::fromStdString(dev::toJS(_b)); +} + +QString ContractCallDataEncoder::toChar(dev::bytes const& _b) { QString str; - if (asString(_b, str)) - return "\"" + str + "\" " + QString::fromStdString(dev::toJS(_b)); - else - return QString::fromStdString(dev::toJS(_b)); + asString(_b, str); + return str; } @@ -269,6 +272,8 @@ QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& return QVariant::fromValue(toString(decodeBool(rawParam))); else if (type == QSolidityType::Type::Bytes || type == QSolidityType::Type::Hash) return QVariant::fromValue(toString(decodeBytes(rawParam))); + else if (type == QSolidityType::Type::String) + return QVariant::fromValue(toChar(decodeBytes(rawParam))); else if (type == QSolidityType::Type::Struct) return QVariant::fromValue(QString("struct")); //TODO else if (type == QSolidityType::Type::Address) diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 629e46b0d..bec048c50 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -71,6 +71,7 @@ private: bool asString(dev::bytes const& _b, QString& _str); QList extractDimension(QString const& _type); void encodeArray(QJsonArray const& _array, QList _dim, SolidityType const& _type, bytes& _content); + QString toChar(dev::bytes const& _b); private: bytes m_encodedData; diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 6fce7686d..f9c7a611c 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -252,8 +252,10 @@ function doCreateProject(title, path) { files: [ contractsFile, indexFile ] }; //TODO: copy from template - fileIo.writeFile(dirPath + indexFile, htmlTemplate); - fileIo.writeFile(dirPath + contractsFile, contractTemplate); + if (!fileIo.fileExists(dirPath + indexFile)) + fileIo.writeFile(dirPath + indexFile, htmlTemplate); + if (!fileIo.fileExists(dirPath + contractsFile)) + fileIo.writeFile(dirPath + contractsFile, contractTemplate); newProject(projectData); var json = JSON.stringify(projectData, null, "\t"); fileIo.writeFile(projectFile, json); @@ -340,7 +342,8 @@ function newContract() { function createAndAddFile(name, extension, content) { var fileName = generateFileName(name, extension); var filePath = projectPath + fileName; - fileIo.writeFile(filePath, content); + if (!fileIo.fileExists(filePath)) + fileIo.writeFile(filePath, content); var id = addFile(fileName); saveProjectFile(); documentAdded(id); From be2ed88d2f6bc265906fee8a4f9589d92bb7d686 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 16 Jun 2015 15:25:29 +0300 Subject: [PATCH 029/103] Coverage script --- getcoverage.sh | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/getcoverage.sh b/getcoverage.sh index 8d34d733c..196629170 100755 --- a/getcoverage.sh +++ b/getcoverage.sh @@ -1,17 +1,33 @@ #!/bin/bash CPP_ETHEREUM_PATH=$(pwd) - -which $CPP_ETHEREUM_PATH/build/test/testeth >/dev/null 2>&1 +BUILD_DIR=$CPP_ETHEREUM_PATH/build +TEST_MODE="" + +for i in "$@" +do +case $i in + -builddir) + shift + ((i++)) + BUILD_DIR=${!i} + shift + ;; + --all) + TEST_MODE="--all" + shift + ;; +esac +done + +which $BUILD_DIR/test/testeth >/dev/null 2>&1 if [ $? != 0 ] then echo "You need to compile and build ethereum with cmake -DPROFILING option to the build dir!" exit; fi -OUTPUT_DIR="$CPP_ETHEREUM_PATH/build/test/coverage" -TESTETH=$CPP_ETHEREUM_PATH/build - +OUTPUT_DIR=$BUILD_DIR/test/coverage if which lcov >/dev/null; then if which genhtml >/dev/null; then echo Cleaning previous report... @@ -19,16 +35,16 @@ if which lcov >/dev/null; then rm -r $OUTPUT_DIR fi mkdir $OUTPUT_DIR - lcov --directory $TESTETH --zerocounters - lcov --capture --initial --directory $TESTETH --output-file $OUTPUT_DIR/coverage_base.info + lcov --directory $BUILD_DIR --zerocounters + lcov --capture --initial --directory $BUILD_DIR --output-file $OUTPUT_DIR/coverage_base.info echo Running testeth... - $CPP_ETHEREUM_PATH/build/test/testeth --all - $CPP_ETHEREUM_PATH/build/test/testeth -t StateTests --jit --all - $CPP_ETHEREUM_PATH/build/test/testeth -t VMTests --jit --all + $CPP_ETHEREUM_PATH/build/test/testeth $TEST_MODE + $CPP_ETHEREUM_PATH/build/test/testeth -t StateTests --jit $TEST_MODE + $CPP_ETHEREUM_PATH/build/test/testeth -t VMTests --jit $TEST_MODE echo Prepearing coverage info... - lcov --capture --directory $TESTETH --output-file $OUTPUT_DIR/coverage_test.info + lcov --capture --directory $BUILD_DIR --output-file $OUTPUT_DIR/coverage_test.info lcov --add-tracefile $OUTPUT_DIR/coverage_base.info --add-tracefile $OUTPUT_DIR/coverage_test.info --output-file $OUTPUT_DIR/coverage_all.info lcov --extract $OUTPUT_DIR/coverage_all.info *cpp-ethereum/* --output-file $OUTPUT_DIR/coverage_export.info genhtml $OUTPUT_DIR/coverage_export.info --output-directory $OUTPUT_DIR/testeth From 93003a12242d56d8025785d1c213151e9e755e62 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 16 Jun 2015 14:58:03 +0200 Subject: [PATCH 030/103] Some changes in libdevcore. --- ethkey/KeyAux.h | 12 +++---- libdevcore/Common.h | 21 ++++++----- libdevcore/CommonData.cpp | 4 +-- libdevcore/CommonData.h | 5 --- libdevcore/CommonIO.cpp | 58 +++++++++---------------------- libdevcore/CommonIO.h | 6 +++- liblll/CodeFragment.cpp | 2 +- libtestutils/Common.cpp | 2 +- lllc/main.cpp | 2 +- solc/CommandLineInterface.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libdevcore/rlp.cpp | 2 +- test/libdevcrypto/SecretStore.cpp | 2 +- test/libdevcrypto/hexPrefix.cpp | 2 +- test/libdevcrypto/trie.cpp | 6 ++-- test/libethcore/dagger.cpp | 2 +- test/libethereum/genesis.cpp | 2 +- 17 files changed, 55 insertions(+), 77 deletions(-) diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index d2ec13b2a..e4310df30 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -221,26 +221,26 @@ public: break; } case OperationMode::ImportBare: - for (string const& i: m_inputs) + for (string const& input: m_inputs) { h128 u; bytes b; - b = fromHex(i); + b = fromHex(input); if (b.size() != 32) { - std::string s = contentsString(i); + std::string s = contentsString(input); b = fromHex(s); if (b.size() != 32) - u = store.importKey(i); + u = store.importKey(input); } if (!u && b.size() == 32) u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); if (!u) { - cerr << "Cannot import " << i << " not a file or secret." << endl; + cerr << "Cannot import " << input << " not a file or secret." << endl; continue; } - cout << "Successfully imported " << i << " as " << toUUID(u); + cout << "Successfully imported " << input << " as " << toUUID(u); } break; case OperationMode::InspectBare: diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 1ee83c794..c6ed25223 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -113,25 +113,27 @@ static const u256 Invalid256 = ~(u256)0; static const bytes NullBytes; static const std::map EmptyMapU256U256; +/// Interprets @a _u as a two's complement signed number and returns the resulting s256. inline s256 u2s(u256 _u) { - static const bigint c_end = (bigint)1 << 256; - static const u256 c_send = (u256)1 << 255; - if (_u < c_send) - return (s256)_u; - else - return (s256)-(c_end - _u); + static const bigint c_end = bigint(1) << 256; + if (boost::multiprecision::bit_test(_u, 255)) + return s256(-(c_end - _u)); + else + return s256(_u); } +/// @returns the two's complement signed representation of the signed number _u. inline u256 s2u(s256 _u) { - static const bigint c_end = (bigint)1 << 256; + static const bigint c_end = bigint(1) << 256; if (_u >= 0) - return (u256)_u; + return u256(_u); else - return (u256)(c_end + _u); + return u256(c_end + _u); } +/// @returns the smallest n >= 0 such that (1 << n) >= _x inline unsigned int toLog2(u256 _x) { unsigned ret; @@ -139,6 +141,7 @@ inline unsigned int toLog2(u256 _x) return ret; } +/// @returns the absolute distance between _a and _b. template inline N diff(N const& _a, N const& _b) { diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index 2d6333f26..ef178965f 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -93,7 +93,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw) if (h != -1) ret.push_back(h); else if (_throw == WhenError::Throw) - throw BadHexCharacter(); + BOOST_THROW_EXCEPTION(BadHexCharacter()); else return bytes(); } @@ -104,7 +104,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw) if (h != -1 && l != -1) ret.push_back((byte)(h * 16 + l)); else if (_throw == WhenError::Throw) - throw BadHexCharacter(); + BOOST_THROW_EXCEPTION(BadHexCharacter()); else return bytes(); } diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index ddc00e09f..f4d3cf65d 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -68,11 +68,6 @@ int fromHex(char _i, WhenError _throw); /// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception. bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow); -#if 0 -std::string toBase58(bytesConstRef _data); -bytes fromBase58(std::string const& _s); -#endif - /// Converts byte array to a string containing the same (binary) data. Unless /// the byte array happens to contain ASCII data, this won't be printable. inline std::string asString(bytes const& _b) diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index 9538ca55f..03b22bfc5 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -64,59 +64,35 @@ string dev::memDump(bytes const& _bytes, unsigned _width, bool _html) return ret.str(); } -// Don't forget to delete[] later. -bytesRef dev::contentsNew(std::string const& _file, bytesRef _dest) +template +inline _T contentsGeneric(std::string const& _file) { + _T ret; + size_t const c_elementSize = sizeof(typename _T::value_type); std::ifstream is(_file, std::ifstream::binary); if (!is) - return bytesRef(); + return ret; + // get length of file: - is.seekg (0, is.end); + is.seekg(0, is.end); streamoff length = is.tellg(); - if (length == 0) // return early, MSVC does not like reading 0 bytes - return bytesRef(); - if (!_dest.empty() && _dest.size() != (unsigned)length) - return bytesRef(); - is.seekg (0, is.beg); - bytesRef ret = _dest.empty() ? bytesRef(new byte[length], length) : _dest; - is.read((char*)ret.data(), length); - is.close(); + if (length == 0) + return ret; // do not read empty file (MSVC does not like it) + is.seekg(0, is.beg); + + ret.resize((length + c_elementSize - 1) / c_elementSize); + is.read(const_cast(reinterpret_cast(ret.data())), length); return ret; } -bytes dev::contents(std::string const& _file) +bytes dev::contents(string const& _file) { - std::ifstream is(_file, std::ifstream::binary); - if (!is) - return bytes(); - // get length of file: - is.seekg (0, is.end); - streamoff length = is.tellg(); - if (length == 0) // return early, MSVC does not like reading 0 bytes - return bytes(); - is.seekg (0, is.beg); - bytes ret(length); - is.read((char*)ret.data(), length); - is.close(); - return ret; + return contentsGeneric(_file); } -string dev::contentsString(std::string const& _file) +string dev::contentsString(string const& _file) { - std::ifstream is(_file, std::ifstream::binary); - if (!is) - return string(); - // get length of file: - is.seekg (0, is.end); - streamoff length = is.tellg(); - if (length == 0) // return early, MSVC does not like reading 0 bytes - return string(); - is.seekg (0, is.beg); - string ret; - ret.resize(length); - is.read((char*)ret.data(), length); - is.close(); - return ret; + return contentsGeneric(_file); } void dev::writeFile(std::string const& _file, bytesConstRef _data) diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h index 46a8b80bc..c8aa830ff 100644 --- a/libdevcore/CommonIO.h +++ b/libdevcore/CommonIO.h @@ -42,10 +42,14 @@ namespace dev { +/// Requests the user to enter a password on the console. std::string getPassword(std::string const& _prompt); -/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes. +/// Retrieve and returns the contents of the given file. +/// If the file doesn't exist or isn't readable, returns an empty container / bytes. bytes contents(std::string const& _file); +/// Retrieve and returns the contents of the given file as a std::string. +/// If the file doesn't exist or isn't readable, returns an empty container / bytes. std::string contentsString(std::string const& _file); /// Retrieve and returns the allocated contents of the given file; if @_dest is given, don't allocate, use it directly. /// If the file doesn't exist or isn't readable, returns bytesRef(). Don't forget to delete [] the returned value's data when finished. diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 1e7766434..b50e316d3 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -196,7 +196,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { if (_t.size() != 2) error(); - m_asm.append(CodeFragment::compile(asString(contents(firstAsString())), _s).m_asm); + m_asm.append(CodeFragment::compile(contentsString(firstAsString()), _s).m_asm); } else if (us == "SET") { diff --git a/libtestutils/Common.cpp b/libtestutils/Common.cpp index cff21d464..8f23685c1 100644 --- a/libtestutils/Common.cpp +++ b/libtestutils/Common.cpp @@ -59,7 +59,7 @@ Json::Value dev::test::loadJsonFromFile(std::string const& _path) { Json::Reader reader; Json::Value result; - string s = asString(dev::contents(_path)); + string s = dev::contentsString(_path); if (!s.length()) ctest << "Contents of " + _path + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"; else diff --git a/lllc/main.cpp b/lllc/main.cpp index 1a44ee950..e1a61f49a 100644 --- a/lllc/main.cpp +++ b/lllc/main.cpp @@ -95,7 +95,7 @@ int main(int argc, char** argv) } } else - src = asString(contents(infile)); + src = contentsString(infile); vector errors; if (src.empty()) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index e65c602ab..ec2a90033 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -401,7 +401,7 @@ bool CommandLineInterface::processInput() continue; } - m_sourceCodes[infile] = asString(dev::contents(infile)); + m_sourceCodes[infile] = dev::contentsString(infile); } m_compiler.reset(new CompilerStack(m_args["add-std"].as())); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 733ccb6d0..bca0528ff 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -598,7 +598,7 @@ void userDefinedTest(std::function doTests) { cnote << "Testing user defined test: " << filename; json_spirit::mValue v; - string s = asString(contents(filename)); + string s = contentsString(filename); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); json_spirit::read_string(s, v); json_spirit::mObject oSingleTest; diff --git a/test/libdevcore/rlp.cpp b/test/libdevcore/rlp.cpp index 41362d569..86780cfa6 100644 --- a/test/libdevcore/rlp.cpp +++ b/test/libdevcore/rlp.cpp @@ -67,7 +67,7 @@ namespace dev string testPath = getTestPath(); testPath += "/BasicTests"; - string s = asString(contents(testPath + "/rlptest.json")); + string s = contentsString(testPath + "/rlptest.json"); BOOST_REQUIRE_MESSAGE( s.length() > 0, "Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp index 1f927db5d..43c201edc 100644 --- a/test/libdevcrypto/SecretStore.cpp +++ b/test/libdevcrypto/SecretStore.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(basic_tests) cnote << "Testing Key Store..."; js::mValue v; - string s = asString(contents(testPath + "/basic_tests.json")); + string s = contentsString(testPath + "/basic_tests.json"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'KeyStoreTests/basic_tests.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); for (auto& i: v.get_obj()) diff --git a/test/libdevcrypto/hexPrefix.cpp b/test/libdevcrypto/hexPrefix.cpp index 53e0d3dbd..4d89ec594 100644 --- a/test/libdevcrypto/hexPrefix.cpp +++ b/test/libdevcrypto/hexPrefix.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(hexPrefix_test) cnote << "Testing Hex-Prefix-Encode..."; js::mValue v; - string s = asString(contents(testPath + "/hexencodetest.json")); + string s = contentsString(testPath + "/hexencodetest.json"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content from 'hexencodetest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); for (auto& i: v.get_obj()) diff --git a/test/libdevcrypto/trie.cpp b/test/libdevcrypto/trie.cpp index b5d8662dc..daa3cc181 100644 --- a/test/libdevcrypto/trie.cpp +++ b/test/libdevcrypto/trie.cpp @@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(hex_encoded_securetrie_test) cnote << "Testing Secure Trie..."; js::mValue v; - string s = asString(contents(testPath + "/hex_encoded_securetrie_test.json")); + string s = contentsString(testPath + "/hex_encoded_securetrie_test.json"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'hex_encoded_securetrie_test.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); for (auto& i: v.get_obj()) @@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(trie_test_anyorder) cnote << "Testing Trie..."; js::mValue v; - string s = asString(contents(testPath + "/trieanyorder.json")); + string s = contentsString(testPath + "/trieanyorder.json"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trieanyorder.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); for (auto& i: v.get_obj()) @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(trie_tests_ordered) cnote << "Testing Trie..."; js::mValue v; - string s = asString(contents(testPath + "/trietest.json")); + string s = contentsString(testPath + "/trietest.json"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 59770373d..1743882e5 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << "Testing Proof of Work..."; js::mValue v; - string s = asString(contents(testPath + "/ethash_tests.json")); + string s = contentsString(testPath + "/ethash_tests.json"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'ethash_tests.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); for (auto& i: v.get_obj()) diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 4633a0617..02ff4517a 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) cnote << "Testing Genesis block..."; js::mValue v; - string s = asString(contents(testPath + "/genesishashestest.json")); + string s = contentsString(testPath + "/genesishashestest.json"); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'genesishashestest.json' is empty. Have you cloned the 'tests' repo branch develop?"); js::read_string(s, v); From c925b2936b428f0354bae9ccf1dc88bdb57f15c1 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Thu, 11 Jun 2015 10:23:04 +0200 Subject: [PATCH 031/103] Bloom Filter introduced --- libwhisper/BloomFilter.cpp | 71 +++++++++++++++++ libwhisper/BloomFilter.h | 73 ++++++++++++++++++ test/libwhisper/bloomFilter.cpp | 133 ++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 libwhisper/BloomFilter.cpp create mode 100644 libwhisper/BloomFilter.h create mode 100644 test/libwhisper/bloomFilter.cpp diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp new file mode 100644 index 000000000..5631688ae --- /dev/null +++ b/libwhisper/BloomFilter.cpp @@ -0,0 +1,71 @@ +/* +This file is part of cpp-ethereum. + +cpp-ethereum is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +cpp-ethereum is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with cpp-ethereum. If not, see . +*/ +/** @file BloomFilter.cpp +* @author Vladislav Gluhovsky +* @date June 2015 +*/ + +#include "BloomFilter.h" + +using namespace std; +using namespace dev; +using namespace dev::shh; + +bool BloomFilter::matches(AbridgedTopic const& _t) const +{ + static unsigned const c_PerfectMatch = ~unsigned(0); + unsigned topic = AbridgedTopic::Arith(_t).convert_to(); + unsigned matchingBits = m_filter & topic; + matchingBits |= ~topic; + return (c_PerfectMatch == matchingBits); +} + +void SharedBloomFilter::add(AbridgedTopic const& _t) +{ + unsigned const topic = AbridgedTopic::Arith(_t).convert_to(); + m_filter |= topic; + + unsigned nextBit = 1; + for (unsigned i = 0; i < ArrSize; ++i, nextBit <<= 1) + if (topic & nextBit) + if (m_refCounter[i] != numeric_limits::max()) + m_refCounter[i]++; + //else: overflow + + // in order to encounter overflow, you have to set 65536 filters simultaneously. + // we assume, it will never happen. +} + +void SharedBloomFilter::remove(AbridgedTopic const& _t) +{ + unsigned const topic = AbridgedTopic::Arith(_t).convert_to(); + + unsigned nextBit = 1; + for (unsigned i = 0; i < ArrSize; ++i, nextBit <<= 1) + if (topic & nextBit) + { + if (m_refCounter[i]) + m_refCounter[i]--; + + if (!m_refCounter[i]) + m_filter &= ~nextBit; + } +} + + + + diff --git a/libwhisper/BloomFilter.h b/libwhisper/BloomFilter.h new file mode 100644 index 000000000..22242ac77 --- /dev/null +++ b/libwhisper/BloomFilter.h @@ -0,0 +1,73 @@ +/* +This file is part of cpp-ethereum. + +cpp-ethereum is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +cpp-ethereum is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with cpp-ethereum. If not, see . +*/ +/** @file BloomFilter.h +* @author Vladislav Gluhovsky +* @date June 2015 +*/ + +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace shh +{ + +class BloomFilter +{ +public: + virtual ~BloomFilter() {} + BloomFilter(): m_filter(0) {} + BloomFilter(unsigned _i): m_filter(_i) {} + BloomFilter(AbridgedTopic const& _t): m_filter(AbridgedTopic::Arith(_t).convert_to()) {} + + bool matches(AbridgedTopic const& _t) const; + virtual void add(AbridgedTopic const& _t) { m_filter |= AbridgedTopic::Arith(_t).convert_to(); } + virtual void remove(AbridgedTopic const& ) {} // not implemented in this class, use derived class instead. + +protected: + unsigned m_filter; +}; + +class SharedBloomFilter: public BloomFilter +{ +public: + virtual ~SharedBloomFilter() {} + SharedBloomFilter() { init(); } + SharedBloomFilter(unsigned _i): BloomFilter(_i) { init(); } + SharedBloomFilter(AbridgedTopic const& _t): BloomFilter(_t) { init(); } + + void add(AbridgedTopic const& _t) override; + void remove(AbridgedTopic const& _t) override; + +protected: + void init() { for (unsigned i = 0; i < ArrSize; ++i) m_refCounter[i] = 0; } + +private: + enum { ArrSize = 8 * AbridgedTopic::size }; + unsigned short m_refCounter[ArrSize]; +}; + +} +} + + + + + + diff --git a/test/libwhisper/bloomFilter.cpp b/test/libwhisper/bloomFilter.cpp new file mode 100644 index 000000000..0a299d53c --- /dev/null +++ b/test/libwhisper/bloomFilter.cpp @@ -0,0 +1,133 @@ +/* +This file is part of cpp-ethereum. + +cpp-ethereum is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +cpp-ethereum is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with cpp-ethereum. If not, see . +*/ +/** @file whisperMessage.cpp +* @author Vladislav Gluhovsky +* @date June 2015 +*/ + +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::shh; + +BOOST_AUTO_TEST_SUITE(bloomFilter) + +BOOST_AUTO_TEST_CASE(match) +{ + VerbosityHolder setTemporaryLevel(10); + cnote << "Testing Bloom Filter matching..."; + + SharedBloomFilter f; + unsigned b00000001 = 0x01; + unsigned b00010000 = 0x10; + unsigned b00011000 = 0x18; + unsigned b00110000 = 0x30; + unsigned b00110010 = 0x32; + unsigned b00111000 = 0x38; + unsigned b00000110 = 0x06; + unsigned b00110110 = 0x36; + unsigned b00110111 = 0x37; + + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); + f.add(AbridgedTopic(b00000001)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000))); + f.add(AbridgedTopic(b00010000)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); + f.add(AbridgedTopic(b00011000)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); + f.add(AbridgedTopic(b00110000)); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); + f.add(AbridgedTopic(b00110010)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); + f.add(AbridgedTopic(b00000110)); + + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110111))); + + f.remove(AbridgedTopic(b00000001)); + f.remove(AbridgedTopic(b00000001)); + f.remove(AbridgedTopic(b00000001)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00011000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); + + f.remove(AbridgedTopic(b00010000)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00011000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); + + f.remove(AbridgedTopic(b00111000)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); + + f.add(AbridgedTopic(b00000001)); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00000001))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00110111))); + + f.remove(AbridgedTopic(b00110111)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); + BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110110))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); + + f.remove(AbridgedTopic(b00110111)); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110110))); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 013ba9966af6cec4f0dd13a9e8982d8c1ad2134c Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 12 Jun 2015 16:31:25 +0200 Subject: [PATCH 032/103] Bloom Filter, first version --- libwhisper/BloomFilter.cpp | 7 ++++--- libwhisper/BloomFilter.h | 7 ++++++- libwhisper/Common.cpp | 22 +++++++++++++++++++++- libwhisper/Common.h | 15 +++------------ libwhisper/WhisperHost.cpp | 4 ++++ libwhisper/WhisperHost.h | 4 +++- test/libwhisper/bloomFilter.cpp | 8 ++++++++ 7 files changed, 49 insertions(+), 18 deletions(-) diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp index 5631688ae..4e1631025 100644 --- a/libwhisper/BloomFilter.cpp +++ b/libwhisper/BloomFilter.cpp @@ -27,11 +27,11 @@ using namespace dev::shh; bool BloomFilter::matches(AbridgedTopic const& _t) const { - static unsigned const c_PerfectMatch = ~unsigned(0); + static unsigned const c_match = ~unsigned(0); unsigned topic = AbridgedTopic::Arith(_t).convert_to(); unsigned matchingBits = m_filter & topic; matchingBits |= ~topic; - return (c_PerfectMatch == matchingBits); + return (c_match == matchingBits); } void SharedBloomFilter::add(AbridgedTopic const& _t) @@ -46,7 +46,8 @@ void SharedBloomFilter::add(AbridgedTopic const& _t) m_refCounter[i]++; //else: overflow - // in order to encounter overflow, you have to set 65536 filters simultaneously. + // in order to encounter overflow, you have to set at least 65536 filters simultaneously. + // even then, the problem will only arise after at least 65536 filters will be be removed. // we assume, it will never happen. } diff --git a/libwhisper/BloomFilter.h b/libwhisper/BloomFilter.h index 22242ac77..d663c994e 100644 --- a/libwhisper/BloomFilter.h +++ b/libwhisper/BloomFilter.h @@ -36,9 +36,14 @@ public: BloomFilter(unsigned _i): m_filter(_i) {} BloomFilter(AbridgedTopic const& _t): m_filter(AbridgedTopic::Arith(_t).convert_to()) {} + unsigned getUnsigned() const { return m_filter; } + AbridgedTopic getAbridgedTopic() const { return AbridgedTopic(m_filter); } + bool matches(AbridgedTopic const& _t) const; + virtual void add(Topic const& _t) { add(abridge(_t)); } + virtual void add(Topics const& _topics) { for (Topic t : _topics) add(abridge(t)); } virtual void add(AbridgedTopic const& _t) { m_filter |= AbridgedTopic::Arith(_t).convert_to(); } - virtual void remove(AbridgedTopic const& ) {} // not implemented in this class, use derived class instead. + virtual void remove(AbridgedTopic const&) {} // not implemented in this class, use derived class instead. protected: unsigned m_filter; diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 526072842..92fd997c5 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -20,9 +20,9 @@ */ #include "Common.h" - #include #include "Message.h" + using namespace std; using namespace dev; using namespace dev::p2p; @@ -84,6 +84,26 @@ bool TopicFilter::matches(Envelope const& _e) const return false; } +TopicFilter::TopicFilter(RLP const& _r) +{ + for (RLP i: _r) + { + m_topicMasks.push_back(TopicMask()); + for (RLP j: i) + m_topicMasks.back().push_back(j.toPair, FixedHash<4>>()); + } +} + +AbridgedTopic TopicFilter::exportBloomFilter() const +{ + AbridgedTopic ret; + for (TopicMask const& t: m_topicMasks) + for (auto i: t) + ret |= i.first; + + return ret; +} + TopicMask BuildTopicMask::toTopicMask() const { TopicMask ret; diff --git a/libwhisper/Common.h b/libwhisper/Common.h index b575166b4..eb624893a 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -48,7 +48,6 @@ using h256Set = dev::h256Set; class WhisperHost; class WhisperPeer; class Whisper; - class Envelope; enum WhisperPacket @@ -91,7 +90,7 @@ protected: h256s m_parts; }; -using TopicMask = std::vector>; +using TopicMask = std::vector>; // where pair::first is the actual abridged topic hash, pair::second is a constant (probably redundunt) using TopicMasks = std::vector; class TopicFilter @@ -101,20 +100,12 @@ public: TopicFilter(Topics const& _m) { m_topicMasks.push_back(TopicMask()); for (auto const& h: _m) m_topicMasks.back().push_back(std::make_pair(abridge(h), h ? ~AbridgedTopic() : AbridgedTopic())); } TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {} TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} - TopicFilter(RLP const& _r)//: m_topicMasks(_r.toVector>()) - { - for (RLP i: _r) - { - m_topicMasks.push_back(TopicMask()); - for (RLP j: i) - m_topicMasks.back().push_back(j.toPair, FixedHash<4>>()); - } - } + TopicFilter(RLP const& _r); void streamRLP(RLPStream& _s) const { _s << m_topicMasks; } h256 sha3() const; - bool matches(Envelope const& _m) const; + AbridgedTopic exportBloomFilter() const; private: TopicMasks m_topicMasks; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 366bb92e4..962abd829 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -113,6 +113,7 @@ unsigned WhisperHost::installWatch(shh::Topics const& _t) if (!m_filters.count(h)) m_filters.insert(make_pair(h, f)); + m_bloom.add(f.filter.exportBloomFilter()); return installWatchOnId(h); } @@ -151,8 +152,11 @@ void WhisperHost::uninstallWatch(unsigned _i) auto fit = m_filters.find(id); if (fit != m_filters.end()) + { + m_bloom.remove(fit->second.filter.exportBloomFilter()); if (!--fit->second.refCount) m_filters.erase(fit); + } } void WhisperHost::doWork() diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 87563d9e8..f66036f89 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -34,6 +34,7 @@ #include "Common.h" #include "WhisperPeer.h" #include "Interface.h" +#include "BloomFilter.h" namespace dev { @@ -60,7 +61,7 @@ public: virtual void uninstallWatch(unsigned _watchId) override; virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } virtual h256s checkWatch(unsigned _watchId) override { cleanup(); dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } - virtual h256s watchMessages(unsigned _watchId) override; + virtual h256s watchMessages(unsigned _watchId) override; /// returns IDs of messages, which match specific watch criteria virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } @@ -86,6 +87,7 @@ private: mutable dev::Mutex m_filterLock; std::map m_filters; std::map m_watches; + SharedBloomFilter m_bloom; }; } diff --git a/test/libwhisper/bloomFilter.cpp b/test/libwhisper/bloomFilter.cpp index 0a299d53c..f58bf8503 100644 --- a/test/libwhisper/bloomFilter.cpp +++ b/test/libwhisper/bloomFilter.cpp @@ -44,6 +44,14 @@ BOOST_AUTO_TEST_CASE(match) unsigned b00110110 = 0x36; unsigned b00110111 = 0x37; + AbridgedTopic x(b00111000); + SharedBloomFilter f1(b00111000); + SharedBloomFilter f2(x); + BOOST_REQUIRE_EQUAL(x, f1.getAbridgedTopic()); + BOOST_REQUIRE_EQUAL(x, f2.getAbridgedTopic()); + BOOST_REQUIRE_EQUAL(b00111000, f1.getUnsigned()); + BOOST_REQUIRE_EQUAL(b00111000, f2.getUnsigned()); + BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); f.add(AbridgedTopic(b00000001)); BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000))); From f7605136578e5fe8ac7b671f1cc41dfcfa2a898a Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Fri, 12 Jun 2015 16:55:41 +0200 Subject: [PATCH 033/103] a minor refactoring --- test/libwhisper/whisperTopic.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/test/libwhisper/whisperTopic.cpp b/test/libwhisper/whisperTopic.cpp index ba487a92e..b5f5cd7d3 100644 --- a/test/libwhisper/whisperTopic.cpp +++ b/test/libwhisper/whisperTopic.cpp @@ -41,8 +41,7 @@ BOOST_FIXTURE_TEST_SUITE(whisper, P2PFixture) BOOST_AUTO_TEST_CASE(topic) { cnote << "Testing Whisper..."; - auto oldLogVerbosity = g_logVerbosity; - g_logVerbosity = 0; + VerbosityHolder setTemporaryLevel(0); Host host1("Test", NetworkPreferences("127.0.0.1", 30303, false)); host1.setIdealPeerCount(1); @@ -99,16 +98,13 @@ BOOST_AUTO_TEST_CASE(topic) } listener.join(); - g_logVerbosity = oldLogVerbosity; - BOOST_REQUIRE_EQUAL(result, 1 + 9 + 25 + 49 + 81); } BOOST_AUTO_TEST_CASE(forwarding) { cnote << "Testing Whisper forwarding..."; - auto oldLogVerbosity = g_logVerbosity; - g_logVerbosity = 0; + VerbosityHolder setTemporaryLevel(0); // Host must be configured not to share peers. Host host1("Listner", NetworkPreferences("127.0.0.1", 30303, false)); @@ -202,16 +198,13 @@ BOOST_AUTO_TEST_CASE(forwarding) listener.join(); done = true; forwarder.join(); - g_logVerbosity = oldLogVerbosity; - BOOST_REQUIRE_EQUAL(result, 1); } BOOST_AUTO_TEST_CASE(asyncforwarding) { cnote << "Testing Whisper async forwarding..."; - auto oldLogVerbosity = g_logVerbosity; - g_logVerbosity = 2; + VerbosityHolder setTemporaryLevel(2); unsigned result = 0; bool done = false; @@ -294,8 +287,6 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) done = true; forwarder.join(); - g_logVerbosity = oldLogVerbosity; - BOOST_REQUIRE_EQUAL(result, 1); } From 255f81e2cc3a71aa78b7c2f11688a158f6fa3bbf Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Tue, 16 Jun 2015 15:30:20 +0200 Subject: [PATCH 034/103] Bloom Filter initial version reviewed --- libwhisper/BloomFilter.cpp | 49 +++---- libwhisper/BloomFilter.h | 48 ++---- libwhisper/WhisperHost.h | 2 +- test/libwhisper/bloomFilter.cpp | 249 +++++++++++++++++++------------- 4 files changed, 184 insertions(+), 164 deletions(-) diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp index 4e1631025..1b6ea7f74 100644 --- a/libwhisper/BloomFilter.cpp +++ b/libwhisper/BloomFilter.cpp @@ -25,48 +25,45 @@ using namespace std; using namespace dev; using namespace dev::shh; -bool BloomFilter::matches(AbridgedTopic const& _t) const -{ - static unsigned const c_match = ~unsigned(0); - unsigned topic = AbridgedTopic::Arith(_t).convert_to(); - unsigned matchingBits = m_filter & topic; - matchingBits |= ~topic; - return (c_match == matchingBits); -} +static unsigned const c_mask[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; -void SharedBloomFilter::add(AbridgedTopic const& _t) +void TopicBloomFilter::add(AbridgedTopic const& _h) { - unsigned const topic = AbridgedTopic::Arith(_t).convert_to(); - m_filter |= topic; - - unsigned nextBit = 1; - for (unsigned i = 0; i < ArrSize; ++i, nextBit <<= 1) - if (topic & nextBit) - if (m_refCounter[i] != numeric_limits::max()) + *this |= _h; + unsigned count = 0; + for (unsigned i = 0; i < CounterSize; ++i) + if (isBitSet(_h, i)) + { + if (m_refCounter[i] != numeric_limits::max()) m_refCounter[i]++; //else: overflow - // in order to encounter overflow, you have to set at least 65536 filters simultaneously. - // even then, the problem will only arise after at least 65536 filters will be be removed. - // we assume, it will never happen. + // in order to encounter overflow, you have to set at least 65536 filters simultaneously. + // even then, the problem will only arise after at least 65536 filters will be be removed. + // we assume, it will never happen. + } } -void SharedBloomFilter::remove(AbridgedTopic const& _t) +void TopicBloomFilter::remove(AbridgedTopic const& _h) { - unsigned const topic = AbridgedTopic::Arith(_t).convert_to(); - - unsigned nextBit = 1; - for (unsigned i = 0; i < ArrSize; ++i, nextBit <<= 1) - if (topic & nextBit) + unsigned count = 0; + for (unsigned i = 0; i < CounterSize; ++i) + if (isBitSet(_h, i)) { if (m_refCounter[i]) m_refCounter[i]--; if (!m_refCounter[i]) - m_filter &= ~nextBit; + (*this)[i/8] &= ~c_mask[i%8]; } } +bool TopicBloomFilter::isBitSet(AbridgedTopic const& _h, unsigned _index) +{ + unsigned iByte = _index / 8; + unsigned iBit = _index % 8; + return (_h[iByte] & c_mask[iBit]) != 0; +} diff --git a/libwhisper/BloomFilter.h b/libwhisper/BloomFilter.h index d663c994e..89529146a 100644 --- a/libwhisper/BloomFilter.h +++ b/libwhisper/BloomFilter.h @@ -28,44 +28,26 @@ namespace dev namespace shh { -class BloomFilter +class TopicBloomFilter: public AbridgedTopic { public: - virtual ~BloomFilter() {} - BloomFilter(): m_filter(0) {} - BloomFilter(unsigned _i): m_filter(_i) {} - BloomFilter(AbridgedTopic const& _t): m_filter(AbridgedTopic::Arith(_t).convert_to()) {} - - unsigned getUnsigned() const { return m_filter; } - AbridgedTopic getAbridgedTopic() const { return AbridgedTopic(m_filter); } - - bool matches(AbridgedTopic const& _t) const; - virtual void add(Topic const& _t) { add(abridge(_t)); } - virtual void add(Topics const& _topics) { for (Topic t : _topics) add(abridge(t)); } - virtual void add(AbridgedTopic const& _t) { m_filter |= AbridgedTopic::Arith(_t).convert_to(); } - virtual void remove(AbridgedTopic const&) {} // not implemented in this class, use derived class instead. - -protected: - unsigned m_filter; -}; - -class SharedBloomFilter: public BloomFilter -{ -public: - virtual ~SharedBloomFilter() {} - SharedBloomFilter() { init(); } - SharedBloomFilter(unsigned _i): BloomFilter(_i) { init(); } - SharedBloomFilter(AbridgedTopic const& _t): BloomFilter(_t) { init(); } - - void add(AbridgedTopic const& _t) override; - void remove(AbridgedTopic const& _t) override; + TopicBloomFilter() { init(); } + TopicBloomFilter(AbridgedTopic const& _h): AbridgedTopic(_h) { init(); } -protected: - void init() { for (unsigned i = 0; i < ArrSize; ++i) m_refCounter[i] = 0; } + void addBloom(AbridgedTopic const& _h) { add(_h.template bloom()); } + void removeBloom(AbridgedTopic const& _h) { remove(_h.template bloom()); } + void add(AbridgedTopic const& _h); + void remove(AbridgedTopic const& _h); + bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloom()); } + enum { BitsPerBloom = 3 }; + private: - enum { ArrSize = 8 * AbridgedTopic::size }; - unsigned short m_refCounter[ArrSize]; + void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; } + static bool isBitSet(AbridgedTopic const& _h, unsigned _index); + + enum { CounterSize = 8 * AbridgedTopic::size }; + std::array m_refCounter; }; } diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index f66036f89..46c41f3a2 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -87,7 +87,7 @@ private: mutable dev::Mutex m_filterLock; std::map m_filters; std::map m_watches; - SharedBloomFilter m_bloom; + TopicBloomFilter m_bloom; }; } diff --git a/test/libwhisper/bloomFilter.cpp b/test/libwhisper/bloomFilter.cpp index f58bf8503..d7a4c76ef 100644 --- a/test/libwhisper/bloomFilter.cpp +++ b/test/libwhisper/bloomFilter.cpp @@ -20,122 +20,163 @@ along with cpp-ethereum. If not, see . */ #include +#include #include using namespace std; using namespace dev; using namespace dev::shh; +void testAddNonExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) +{ + BOOST_REQUIRE(!_f.contains(_h)); + _f.add(_h); + BOOST_REQUIRE(_f.contains(_h)); +} + +void testRemoveExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) +{ + BOOST_REQUIRE(_f.contains(_h)); + _f.remove(_h); + BOOST_REQUIRE(!_f.contains(_h)); +} + +void testAddNonExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) +{ + BOOST_REQUIRE(!_f.containsBloom(_h)); + _f.addBloom(_h); + BOOST_REQUIRE(_f.containsBloom(_h)); +} + +void testRemoveExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) +{ + BOOST_REQUIRE(_f.containsBloom(_h)); + _f.removeBloom(_h); + BOOST_REQUIRE(!_f.containsBloom(_h)); +} + BOOST_AUTO_TEST_SUITE(bloomFilter) -BOOST_AUTO_TEST_CASE(match) +BOOST_AUTO_TEST_CASE(bloomFilterRandom) { VerbosityHolder setTemporaryLevel(10); cnote << "Testing Bloom Filter matching..."; - SharedBloomFilter f; - unsigned b00000001 = 0x01; - unsigned b00010000 = 0x10; - unsigned b00011000 = 0x18; - unsigned b00110000 = 0x30; - unsigned b00110010 = 0x32; - unsigned b00111000 = 0x38; - unsigned b00000110 = 0x06; - unsigned b00110110 = 0x36; - unsigned b00110111 = 0x37; - - AbridgedTopic x(b00111000); - SharedBloomFilter f1(b00111000); - SharedBloomFilter f2(x); - BOOST_REQUIRE_EQUAL(x, f1.getAbridgedTopic()); - BOOST_REQUIRE_EQUAL(x, f2.getAbridgedTopic()); - BOOST_REQUIRE_EQUAL(b00111000, f1.getUnsigned()); - BOOST_REQUIRE_EQUAL(b00111000, f2.getUnsigned()); - - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - f.add(AbridgedTopic(b00000001)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000))); - f.add(AbridgedTopic(b00010000)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - f.add(AbridgedTopic(b00011000)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); - f.add(AbridgedTopic(b00110000)); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); - f.add(AbridgedTopic(b00110010)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); - f.add(AbridgedTopic(b00000110)); - - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00000001)); - f.remove(AbridgedTopic(b00000001)); - f.remove(AbridgedTopic(b00000001)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00010000)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00111000)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); - - f.add(AbridgedTopic(b00000001)); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00110111)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); - - f.remove(AbridgedTopic(b00110111)); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000001))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00010000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00011000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110010))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00111000))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00000110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110110))); - BOOST_REQUIRE(!f.matches(AbridgedTopic(b00110111))); + TopicBloomFilter f; + vector vec; + Topic x(0xDEADBEEF); + int const c_rounds = 4; + + for (int i = 0; i < c_rounds; ++i, x = sha3(x)) + vec.push_back(abridge(x)); + + for (int i = 0; i < c_rounds; ++i) + testAddNonExisting(f, vec[i]); + + for (int i = 0; i < c_rounds; ++i) + testRemoveExisting(f, vec[i]); + + for (int i = 0; i < c_rounds; ++i) + testAddNonExistingBloom(f, vec[i]); + + for (int i = 0; i < c_rounds; ++i) + testRemoveExistingBloom(f, vec[i]); +} + +BOOST_AUTO_TEST_CASE(bloomFilterRaw) +{ + VerbosityHolder setTemporaryLevel(10); + cnote << "Testing Raw Bloom matching..."; + + TopicBloomFilter f; + + AbridgedTopic b00000001(0x01); + AbridgedTopic b00010000(0x10); + AbridgedTopic b00011000(0x18); + AbridgedTopic b00110000(0x30); + AbridgedTopic b00110010(0x32); + AbridgedTopic b00111000(0x38); + AbridgedTopic b00000110(0x06); + AbridgedTopic b00110110(0x36); + AbridgedTopic b00110111(0x37); + + testAddNonExisting(f, b00000001); + testAddNonExisting(f, b00010000); + testAddNonExisting(f, b00011000); + testAddNonExisting(f, b00110000); + BOOST_REQUIRE(f.contains(b00111000)); + testAddNonExisting(f, b00110010); + testAddNonExisting(f, b00000110); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(f.contains(b00110111)); + + f.remove(b00000001); + f.remove(b00000001); + f.remove(b00000001); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(f.contains(b00011000)); + BOOST_REQUIRE(f.contains(b00110000)); + BOOST_REQUIRE(f.contains(b00110010)); + BOOST_REQUIRE(f.contains(b00111000)); + BOOST_REQUIRE(f.contains(b00000110)); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); + + f.remove(b00010000); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(f.contains(b00011000)); + BOOST_REQUIRE(f.contains(b00110000)); + BOOST_REQUIRE(f.contains(b00110010)); + BOOST_REQUIRE(f.contains(b00111000)); + BOOST_REQUIRE(f.contains(b00000110)); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); + + f.remove(b00111000); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(!f.contains(b00011000)); + BOOST_REQUIRE(f.contains(b00110000)); + BOOST_REQUIRE(f.contains(b00110010)); + BOOST_REQUIRE(!f.contains(b00111000)); + BOOST_REQUIRE(f.contains(b00000110)); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); + + f.add(b00000001); + BOOST_REQUIRE(f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(!f.contains(b00011000)); + BOOST_REQUIRE(f.contains(b00110000)); + BOOST_REQUIRE(f.contains(b00110010)); + BOOST_REQUIRE(!f.contains(b00111000)); + BOOST_REQUIRE(f.contains(b00000110)); + BOOST_REQUIRE(f.contains(b00110110)); + BOOST_REQUIRE(f.contains(b00110111)); + + f.remove(b00110111); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(f.contains(b00010000)); + BOOST_REQUIRE(!f.contains(b00011000)); + BOOST_REQUIRE(!f.contains(b00110000)); + BOOST_REQUIRE(!f.contains(b00110010)); + BOOST_REQUIRE(!f.contains(b00111000)); + BOOST_REQUIRE(!f.contains(b00000110)); + BOOST_REQUIRE(!f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); + + f.remove(b00110111); + BOOST_REQUIRE(!f.contains(b00000001)); + BOOST_REQUIRE(!f.contains(b00010000)); + BOOST_REQUIRE(!f.contains(b00011000)); + BOOST_REQUIRE(!f.contains(b00110000)); + BOOST_REQUIRE(!f.contains(b00110010)); + BOOST_REQUIRE(!f.contains(b00111000)); + BOOST_REQUIRE(!f.contains(b00000110)); + BOOST_REQUIRE(!f.contains(b00110110)); + BOOST_REQUIRE(!f.contains(b00110111)); } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 267b24bea683467ab89035adecb953cd548c4dcb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 16 Jun 2015 21:35:57 +0800 Subject: [PATCH 035/103] Support changing miner in eth. --- eth/main.cpp | 2 ++ libweb3jsonrpc/WebThreeStubServer.cpp | 11 ++++++++++- libweb3jsonrpc/WebThreeStubServer.h | 5 ++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 382858ae7..32862edf1 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -827,6 +827,7 @@ int main(int argc, char** argv) { jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); + jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; }); jsonrpcServer->StartListening(); if (jsonAdmin.empty()) jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); @@ -982,6 +983,7 @@ int main(int argc, char** argv) jsonrpc = SensibleHttpPort; jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); + jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; }); jsonrpcServer->StartListening(); if (jsonAdmin.empty()) jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index adef51033..a6ea52eda 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -205,7 +205,16 @@ Json::Value WebThreeStubServer::admin_eth_newAccount(Json::Value const& _info, s bool WebThreeStubServer::admin_eth_setMiningBenefactor(std::string const& _uuidOrAddress, std::string const& _session) { ADMIN; - (void)_uuidOrAddress; + Address a; + h128 uuid = fromUUID(_uuidOrAddress); + if (uuid) + a = m_keyMan.address(uuid); + else if (isHash
(_uuidOrAddress)) + a = Address(_uuidOrAddress); + else + throw jsonrpc::JsonRpcException("Invalid UUID or address"); + if (m_setMiningBenefactor) + m_setMiningBenefactor(a); return true; } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index ecf8acca0..290bf456c 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -60,6 +60,8 @@ public: std::string newSession(SessionPermissions const& _p); void addSession(std::string const& _session, SessionPermissions const& _p) { m_sessions[_session] = _p; } + virtual void setMiningBenefactorChanger(std::function const& _f) { m_setMiningBenefactor = _f; } + private: virtual bool hasPriviledgeLevel(std::string const& _session, Priviledge _l) const override { auto it = m_sessions.find(_session); return it != m_sessions.end() && it->second.priviledges.count(_l); } @@ -80,9 +82,9 @@ private: virtual std::string admin_eth_blockQueueFirstUnknown(std::string const& _session) override; virtual bool admin_eth_blockQueueRetryUnknown(std::string const& _session) override; + virtual bool admin_eth_setMiningBenefactor(std::string const& _uuidOrAddress, std::string const& _session) override; virtual Json::Value admin_eth_allAccounts(std::string const& _session) override; virtual Json::Value admin_eth_newAccount(const Json::Value& _info, std::string const& _session) override; - virtual bool admin_eth_setMiningBenefactor(std::string const& _uuidOrAddress, std::string const& _session) override; virtual Json::Value admin_eth_inspect(std::string const& _address, std::string const& _session) override; virtual Json::Value admin_eth_reprocess(std::string const& _blockNumberOrHash, std::string const& _session) override; virtual Json::Value admin_eth_vmTrace(std::string const& _blockNumberOrHash, int _txIndex, std::string const& _session) override; @@ -101,6 +103,7 @@ private: leveldb::WriteOptions m_writeOptions; leveldb::DB* m_db; + std::function m_setMiningBenefactor; std::unordered_map m_sessions; }; From 4c854e8e9750847cc39c717cf9df8b4a7d79c861 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Tue, 16 Jun 2015 15:54:07 +0200 Subject: [PATCH 036/103] rebased on the latest develop --- libwhisper/BloomFilter.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libwhisper/BloomFilter.h b/libwhisper/BloomFilter.h index 89529146a..188e69f59 100644 --- a/libwhisper/BloomFilter.h +++ b/libwhisper/BloomFilter.h @@ -34,11 +34,11 @@ public: TopicBloomFilter() { init(); } TopicBloomFilter(AbridgedTopic const& _h): AbridgedTopic(_h) { init(); } - void addBloom(AbridgedTopic const& _h) { add(_h.template bloom()); } - void removeBloom(AbridgedTopic const& _h) { remove(_h.template bloom()); } + void addBloom(AbridgedTopic const& _h) { add(_h.template bloomPart()); } + void removeBloom(AbridgedTopic const& _h) { remove(_h.template bloomPart()); } void add(AbridgedTopic const& _h); void remove(AbridgedTopic const& _h); - bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloom()); } + bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloomPart()); } enum { BitsPerBloom = 3 }; From 5848faeb49112d15b963ccab0132ad1c9b24aa30 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 16 Jun 2015 16:08:40 +0200 Subject: [PATCH 037/103] Some documentation and checks for vector_ref. --- libdevcore/vector_ref.h | 25 ++++++++++++++++++++++--- libevmasm/Assembly.cpp | 10 ---------- libevmasm/AssemblyItem.cpp | 7 ------- libevmasm/AssemblyItem.h | 9 ++++++--- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index b04d449b3..98c6adb21 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -9,6 +9,9 @@ namespace dev { +/** + * A modifiable reference to an existing object or vector in memory. + */ template class vector_ref { @@ -17,34 +20,50 @@ public: using element_type = _T; using mutable_value_type = typename std::conditional::value, typename std::remove_const<_T>::type, _T>::type; + static_assert(std::is_pod::value, "vector_ref can only be used with PODs due to its low-level treatment of data."); + vector_ref(): m_data(nullptr), m_count(0) {} + /// Creates a new vector_ref to point to @a _count elements starting at @a _data. vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} + /// Creates a new vector_ref pointing to the data part of a string (given as pointer). vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {} + /// Creates a new vector_ref pointing to the data part of a vector (given as pointer). vector_ref(typename std::conditional::value, std::vector::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} - vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {} + /// Creates a new vector_ref pointing to the data part of a string (given as reference). + vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T)) {} #ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ vector_ref(leveldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {} #endif explicit operator bool() const { return m_data && m_count; } - bool contentsEqual(std::vector const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); } + bool contentsEqual(std::vector const& _c) const { if (!m_data || m_count == 0) return _c.empty(); else return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count * sizeof(_T)); } std::vector toVector() const { return std::vector(m_data, m_data + m_count); } std::vector toBytes() const { return std::vector(reinterpret_cast(m_data), reinterpret_cast(m_data) + m_count * sizeof(_T)); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); } + template explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); } operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } _T* data() const { return m_data; } + /// @returns the number of elements referenced (not necessarily number of bytes). size_t count() const { return m_count; } + /// @returns the number of elements referenced (not necessarily number of bytes). size_t size() const { return m_count; } bool empty() const { return !m_count; } - vector_ref<_T> next() const { return vector_ref<_T>(m_data + m_count, m_count); } + /// @returns a new vector_ref pointing at the next chunk of @a size() elements. + vector_ref<_T> next() const { if (!m_data) return *this; else return vector_ref<_T>(m_data + m_count, m_count); } + /// @returns a new vector_ref which is a shifted and shortened view of the original data. + /// If this goes out of bounds in any way, returns an empty vector_ref. + /// If @a _count is ~size_t(0), extends the view to the end of the data. vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); } + /// @returns a new vector_ref which is a shifted view of the original data (not going beyond it). vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); } void retarget(_T* _d, size_t _s) { m_data = _d; m_count = _s; } void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); } template bool overlapsWith(vector_ref _t) const { void const* f1 = data(); void const* t1 = data() + size(); void const* f2 = _t.data(); void const* t2 = _t.data() + _t.size(); return f1 < t2 && t1 > f2; } + /// Copies the contents of this vector_ref to the contents of @a _t, up to the max size of @a _t. void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } + /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t. void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } _T* begin() { return m_data; } diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 3557fc0ee..34ee05966 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -292,16 +292,6 @@ void Assembly::injectStart(AssemblyItem const& _i) m_items.insert(m_items.begin(), _i); } -inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) -{ - if (_a.size() != _b.size()) - return false; - for (unsigned i = 0; i < _a.size(); ++i) - if (!_a[i].match(_b[i])) - return false; - return true; -} - struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; #define copt dev::LogOutputStream() diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index a4485a144..a0c5e19a6 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -126,10 +126,3 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item) } return _out; } - -ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) -{ - for (AssemblyItem const& i: _i) - _out << i; - return _out; -} diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 9eca0a7d1..3fa9bb203 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -98,11 +98,14 @@ private: }; using AssemblyItems = std::vector; -using AssemblyItemsConstRef = vector_ref; std::ostream& operator<<(std::ostream& _out, AssemblyItem const& _item); -std::ostream& operator<<(std::ostream& _out, AssemblyItemsConstRef _i); -inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { return operator<<(_out, AssemblyItemsConstRef(&_i)); } +inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _items) +{ + for (AssemblyItem const& item: _items) + _out << item; + return _out; +} } } From b046146d48e80d7a0e678060d696403f05d15a9a Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Tue, 16 Jun 2015 16:17:29 +0200 Subject: [PATCH 038/103] unused variable removed --- libwhisper/BloomFilter.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp index 1b6ea7f74..e02b6e1d0 100644 --- a/libwhisper/BloomFilter.cpp +++ b/libwhisper/BloomFilter.cpp @@ -30,7 +30,6 @@ static unsigned const c_mask[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; void TopicBloomFilter::add(AbridgedTopic const& _h) { *this |= _h; - unsigned count = 0; for (unsigned i = 0; i < CounterSize; ++i) if (isBitSet(_h, i)) { @@ -46,7 +45,6 @@ void TopicBloomFilter::add(AbridgedTopic const& _h) void TopicBloomFilter::remove(AbridgedTopic const& _h) { - unsigned count = 0; for (unsigned i = 0; i < CounterSize; ++i) if (isBitSet(_h, i)) { From 63ad9620416f2d593db6e2b730fd5e2dfabf6355 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 16 Jun 2015 16:35:50 +0200 Subject: [PATCH 039/103] fix #2194 --- mix/ContractCallDataEncoder.cpp | 16 +++++++++++----- mix/qml/QStringTypeView.qml | 15 +++++++++++++-- mix/qml/js/InputValidator.js | 10 +++++++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 8f5f3ecc7..e67ce9cea 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -80,10 +80,7 @@ void ContractCallDataEncoder::encodeArray(QJsonArray const& _array, QList _ if (c.isArray()) { if (_dim[0] == -1) - { - m_dynamicOffsetMap.push_back(std::make_pair(m_dynamicData.size() + offsetStart + 32 + k * 32, - m_dynamicData.size() + _content.size())); - } + m_dynamicOffsetMap.push_back(std::make_pair(m_dynamicData.size() + offsetStart + 32 + k * 32, m_dynamicData.size() + _content.size())); encodeArray(c.toArray(), _dim, _type, _content); } else @@ -183,6 +180,11 @@ unsigned ContractCallDataEncoder::encodeSingleItem(QString const& _data, Solidit catch (std::exception const&) { // manage input as a string. + QRegExp strExtract("\"(.*)\""); //check if contains both string and hex value, keep the string. + int i = strExtract.indexIn(src); + if (i != -1) + src = strExtract.cap(0); + src = src.replace("\"", ""); result = encodeStringParam(src, alignSize); } } @@ -249,7 +251,11 @@ dev::bytes ContractCallDataEncoder::decodeBytes(dev::bytes const& _rawValue) QString ContractCallDataEncoder::toString(dev::bytes const& _b) { - return QString::fromStdString(dev::toJS(_b)); + QString str; + if (asString(_b, str)) + return "\"" + str + "\" " + QString::fromStdString(dev::toJS(_b)); + else + return QString::fromStdString(dev::toJS(_b)); } QString ContractCallDataEncoder::toChar(dev::bytes const& _b) diff --git a/mix/qml/QStringTypeView.qml b/mix/qml/QStringTypeView.qml index 080c49282..101863421 100644 --- a/mix/qml/QStringTypeView.qml +++ b/mix/qml/QStringTypeView.qml @@ -2,11 +2,15 @@ import QtQuick 2.0 Item { - property alias value: textinput.text + property string value property alias readOnly: textinput.readOnly id: editRoot height: 20 width: readOnly ? textinput.implicitWidth : 150 + onValueChanged: + { + textinput.text = value + } SourceSansProBold { @@ -18,12 +22,19 @@ Item radius: 4 TextInput { id: textinput - text: value clip: true anchors.fill: parent wrapMode: Text.WrapAnywhere font.family: boldFont.name selectByMouse: true + onTextChanged: { + var stringRegEx = new RegExp('"^\\"*', "g") + var str = stringRegEx.exec(text) + if (str && str.length > 0) + value = str[0] + else + value = text + } } } } diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js index 8a8ef1715..aa3b90150 100644 --- a/mix/qml/js/InputValidator.js +++ b/mix/qml/js/InputValidator.js @@ -187,7 +187,15 @@ function validateAddress(_type, _value) function validateBytes(_type, _value) { var ret = { valid: true, message: "" } - if (_value.length > parseInt(_type.replace("bytes", "")) ) + if (_value.indexOf("\"") === 0 && _value.indexOf("0x") !== -1) + { + //this is a different fomatting + var stringRegEx = new RegExp('".*"', "g"); + var matches = _value.match(stringRegEx); + if (matches.length === 1) + _value = matches[0] + } + if (_type !== "bytes" && _value.length > parseInt(_type.replace("bytes", "")) ) { ret.valid = false; ret.message = _type + " should not contains more than " + _type.replace("bytes", "") + " characters"; From af4d1b027ca349b8e14e48c3da131ed2600ffc20 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 16 Jun 2015 16:59:02 +0200 Subject: [PATCH 040/103] bux fixes --- mix/qml/js/InputValidator.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js index aa3b90150..46b23274d 100644 --- a/mix/qml/js/InputValidator.js +++ b/mix/qml/js/InputValidator.js @@ -110,9 +110,8 @@ function validateArray(_type, _value) var dim = _type.match(arrayRegEx) dim.reverse(); for (var k = 0; k < dim.length; k++) - { _type = _type.replace(dim[k], "") - } + _type = _type.replace(/calldata/g, "") return checkArrayRecursively(_type, dim, _value) } From c75c72a99443acca133c8f35efc3332f79f46bde Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 16 Jun 2015 17:20:41 +0200 Subject: [PATCH 041/103] Type conversion specialities for storage references. --- libsolidity/CompilerUtils.cpp | 9 ++++++--- libsolidity/ExpressionCompiler.cpp | 23 +++++++++++------------ libsolidity/Types.h | 3 +++ test/libsolidity/SolidityEndToEndTest.cpp | 10 +++++----- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 349877a29..d4e705a3c 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -274,10 +274,13 @@ void CompilerUtils::encodeToMemory( else { copyToStackTop(argSize - stackPos + dynPointers + 2, _givenTypes[i]->getSizeOnStack()); - if (targetType->isValueType()) - convertType(*_givenTypes[i], *targetType, true); solAssert(!!targetType, "Externalable type expected."); - storeInMemoryDynamic(*targetType, _padToWordBoundaries); + TypePointer type = targetType; + if (_givenTypes[i]->isInStorage()) + type = _givenTypes[i]; // delay conversion + else + convertType(*_givenTypes[i], *targetType, true); + storeInMemoryDynamic(*type, _padToWordBoundaries); } stackPos += _givenTypes[i]->getSizeOnStack(); } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 12274c7ab..c98d76f3f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -146,10 +146,13 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) { CompilerContext::LocationSetter locationSetter(m_context, _assignment); _assignment.getRightHandSide().accept(*this); - if (_assignment.getType()->isValueType()) - utils().convertType(*_assignment.getRightHandSide().getType(), *_assignment.getType()); - // We need this conversion mostly in the case of compound assignments. For non-value types - // the conversion is done in LValue::storeValue. + TypePointer type = _assignment.getRightHandSide().getType(); + if (!_assignment.getType()->isInStorage()) + { + utils().convertType(*type, *_assignment.getType()); + type = _assignment.getType(); + } + _assignment.getLeftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); @@ -175,7 +178,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_context << eth::swapInstruction(itemSize + lvalueSize) << eth::Instruction::POP; } } - m_currentLValue->storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); + m_currentLValue->storeValue(*type, _assignment.getLocation()); m_currentLValue.reset(); return false; } @@ -1119,14 +1122,10 @@ void ExpressionCompiler::appendExternalFunctionCall( void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression) { + solAssert(_expectedType.isValueType(), "Not implemented for non-value types."); _expression.accept(*this); - if (_expectedType.isValueType()) - { - utils().convertType(*_expression.getType(), _expectedType, true); - utils().storeInMemoryDynamic(_expectedType); - } - else - utils().storeInMemoryDynamic(*_expression.getType()->mobileType()); + utils().convertType(*_expression.getType(), _expectedType, true); + utils().storeInMemoryDynamic(_expectedType); } void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 0f86ac95f..70f7807c8 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -202,6 +202,8 @@ public: /// This returns the corresponding integer type for IntegerConstantTypes and the pointer type /// for storage reference types. virtual TypePointer mobileType() const { return shared_from_this(); } + /// @returns true if this type is a storage pointer or reference. + virtual bool isInStorage() const { return false; } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } @@ -374,6 +376,7 @@ public: virtual TypePointer copyForLocation(Location _location, bool _isPointer) const = 0; virtual TypePointer mobileType() const override { return copyForLocation(m_location, true); } + virtual bool isInStorage() const override { return m_location == Location::Storage; } /// Storage references can be pointers or bound references. In general, local variables are of /// pointer type, state variables are bound references. Assignments to pointers or deleting diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f4d875e77..109481edc 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4243,9 +4243,9 @@ BOOST_AUTO_TEST_CASE(return_string) function get1() returns (string r) { return s; } -// function get2() returns (string r) { -// r = s; -// } + function get2() returns (string r) { + r = s; + } } )"; compileAndRun(sourceCode, 0, "Main"); @@ -4253,8 +4253,8 @@ BOOST_AUTO_TEST_CASE(return_string) bytes args = encodeArgs(u256(0x20), u256(s.length()), s); BOOST_REQUIRE(callContractFunction("set(string)", asString(args)) == encodeArgs()); BOOST_CHECK(callContractFunction("get1()") == args); -// BOOST_CHECK(callContractFunction("get2()") == args); -// BOOST_CHECK(callContractFunction("s()") == args); + BOOST_CHECK(callContractFunction("get2()") == args); + BOOST_CHECK(callContractFunction("s()") == args); } BOOST_AUTO_TEST_SUITE_END() From c449a648b4174f9aa8955ffcdfb939e83bd6d35e Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Tue, 16 Jun 2015 23:17:59 +0200 Subject: [PATCH 042/103] naming conventions changed --- libwhisper/BloomFilter.cpp | 4 ++-- libwhisper/BloomFilter.h | 12 +++++++----- libwhisper/Common.cpp | 5 +++-- libwhisper/Common.h | 2 +- libwhisper/WhisperHost.cpp | 4 ++-- test/libwhisper/bloomFilter.cpp | 28 ++++++++++++++-------------- 6 files changed, 29 insertions(+), 26 deletions(-) diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp index e02b6e1d0..c189ee912 100644 --- a/libwhisper/BloomFilter.cpp +++ b/libwhisper/BloomFilter.cpp @@ -27,7 +27,7 @@ using namespace dev::shh; static unsigned const c_mask[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; -void TopicBloomFilter::add(AbridgedTopic const& _h) +void TopicBloomFilter::addRaw(AbridgedTopic const& _h) { *this |= _h; for (unsigned i = 0; i < CounterSize; ++i) @@ -43,7 +43,7 @@ void TopicBloomFilter::add(AbridgedTopic const& _h) } } -void TopicBloomFilter::remove(AbridgedTopic const& _h) +void TopicBloomFilter::removeRaw(AbridgedTopic const& _h) { for (unsigned i = 0; i < CounterSize; ++i) if (isBitSet(_h, i)) diff --git a/libwhisper/BloomFilter.h b/libwhisper/BloomFilter.h index 188e69f59..0ca460805 100644 --- a/libwhisper/BloomFilter.h +++ b/libwhisper/BloomFilter.h @@ -34,19 +34,21 @@ public: TopicBloomFilter() { init(); } TopicBloomFilter(AbridgedTopic const& _h): AbridgedTopic(_h) { init(); } - void addBloom(AbridgedTopic const& _h) { add(_h.template bloomPart()); } - void removeBloom(AbridgedTopic const& _h) { remove(_h.template bloomPart()); } - void add(AbridgedTopic const& _h); - void remove(AbridgedTopic const& _h); + void addBloom(AbridgedTopic const& _h) { addRaw(_h.template bloomPart()); } + void removeBloom(AbridgedTopic const& _h) { removeRaw(_h.template bloomPart()); } bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloomPart()); } + void addRaw(AbridgedTopic const& _h); + void removeRaw(AbridgedTopic const& _h); + bool containsRaw(AbridgedTopic const& _h) const { return contains(_h); } + enum { BitsPerBloom = 3 }; private: void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; } static bool isBitSet(AbridgedTopic const& _h, unsigned _index); - enum { CounterSize = 8 * AbridgedTopic::size }; + enum { CounterSize = 8 * TopicBloomFilter::size }; std::array m_refCounter; }; diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 92fd997c5..5dc267fcf 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -22,6 +22,7 @@ #include "Common.h" #include #include "Message.h" +#include "BloomFilter.h" using namespace std; using namespace dev; @@ -94,12 +95,12 @@ TopicFilter::TopicFilter(RLP const& _r) } } -AbridgedTopic TopicFilter::exportBloomFilter() const +AbridgedTopic TopicFilter::exportBloom() const { AbridgedTopic ret; for (TopicMask const& t: m_topicMasks) for (auto i: t) - ret |= i.first; + ret |= i.first.template bloomPart(); return ret; } diff --git a/libwhisper/Common.h b/libwhisper/Common.h index eb624893a..07c5b3317 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -105,7 +105,7 @@ public: void streamRLP(RLPStream& _s) const { _s << m_topicMasks; } h256 sha3() const; bool matches(Envelope const& _m) const; - AbridgedTopic exportBloomFilter() const; + AbridgedTopic exportBloom() const; private: TopicMasks m_topicMasks; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 962abd829..d6759df6f 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -113,7 +113,7 @@ unsigned WhisperHost::installWatch(shh::Topics const& _t) if (!m_filters.count(h)) m_filters.insert(make_pair(h, f)); - m_bloom.add(f.filter.exportBloomFilter()); + m_bloom.addRaw(f.filter.exportBloom()); return installWatchOnId(h); } @@ -153,7 +153,7 @@ void WhisperHost::uninstallWatch(unsigned _i) auto fit = m_filters.find(id); if (fit != m_filters.end()) { - m_bloom.remove(fit->second.filter.exportBloomFilter()); + m_bloom.removeRaw(fit->second.filter.exportBloom()); if (!--fit->second.refCount) m_filters.erase(fit); } diff --git a/test/libwhisper/bloomFilter.cpp b/test/libwhisper/bloomFilter.cpp index d7a4c76ef..adf76c429 100644 --- a/test/libwhisper/bloomFilter.cpp +++ b/test/libwhisper/bloomFilter.cpp @@ -29,16 +29,16 @@ using namespace dev::shh; void testAddNonExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) { - BOOST_REQUIRE(!_f.contains(_h)); - _f.add(_h); - BOOST_REQUIRE(_f.contains(_h)); + BOOST_REQUIRE(!_f.containsRaw(_h)); + _f.addRaw(_h); + BOOST_REQUIRE(_f.containsRaw(_h)); } void testRemoveExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) { - BOOST_REQUIRE(_f.contains(_h)); - _f.remove(_h); - BOOST_REQUIRE(!_f.contains(_h)); + BOOST_REQUIRE(_f.containsRaw(_h)); + _f.removeRaw(_h); + BOOST_REQUIRE(!_f.containsRaw(_h)); } void testAddNonExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) @@ -110,9 +110,9 @@ BOOST_AUTO_TEST_CASE(bloomFilterRaw) BOOST_REQUIRE(f.contains(b00110110)); BOOST_REQUIRE(f.contains(b00110111)); - f.remove(b00000001); - f.remove(b00000001); - f.remove(b00000001); + f.removeRaw(b00000001); + f.removeRaw(b00000001); + f.removeRaw(b00000001); BOOST_REQUIRE(!f.contains(b00000001)); BOOST_REQUIRE(f.contains(b00010000)); BOOST_REQUIRE(f.contains(b00011000)); @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRaw) BOOST_REQUIRE(f.contains(b00110110)); BOOST_REQUIRE(!f.contains(b00110111)); - f.remove(b00010000); + f.removeRaw(b00010000); BOOST_REQUIRE(!f.contains(b00000001)); BOOST_REQUIRE(f.contains(b00010000)); BOOST_REQUIRE(f.contains(b00011000)); @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRaw) BOOST_REQUIRE(f.contains(b00110110)); BOOST_REQUIRE(!f.contains(b00110111)); - f.remove(b00111000); + f.removeRaw(b00111000); BOOST_REQUIRE(!f.contains(b00000001)); BOOST_REQUIRE(f.contains(b00010000)); BOOST_REQUIRE(!f.contains(b00011000)); @@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRaw) BOOST_REQUIRE(f.contains(b00110110)); BOOST_REQUIRE(!f.contains(b00110111)); - f.add(b00000001); + f.addRaw(b00000001); BOOST_REQUIRE(f.contains(b00000001)); BOOST_REQUIRE(f.contains(b00010000)); BOOST_REQUIRE(!f.contains(b00011000)); @@ -156,7 +156,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRaw) BOOST_REQUIRE(f.contains(b00110110)); BOOST_REQUIRE(f.contains(b00110111)); - f.remove(b00110111); + f.removeRaw(b00110111); BOOST_REQUIRE(!f.contains(b00000001)); BOOST_REQUIRE(f.contains(b00010000)); BOOST_REQUIRE(!f.contains(b00011000)); @@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRaw) BOOST_REQUIRE(!f.contains(b00110110)); BOOST_REQUIRE(!f.contains(b00110111)); - f.remove(b00110111); + f.removeRaw(b00110111); BOOST_REQUIRE(!f.contains(b00000001)); BOOST_REQUIRE(!f.contains(b00010000)); BOOST_REQUIRE(!f.contains(b00011000)); From 2ad9a6d265ad2ab7b4d4ae97a3226082d50b3396 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Jun 2015 10:06:00 +0200 Subject: [PATCH 043/103] reverted to old pv61 sync code --- libethcore/Common.h | 3 +- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChainSync.cpp | 701 +++++++++++++++++++++++++++++++++ libethereum/BlockChainSync.h | 146 +++++++ libethereum/BlockQueue.cpp | 3 +- libethereum/CommonNet.h | 6 +- libethereum/EthereumHost.cpp | 578 +++------------------------ libethereum/EthereumHost.h | 64 +-- libethereum/EthereumPeer.cpp | 11 +- libethereum/EthereumPeer.h | 16 +- 10 files changed, 941 insertions(+), 589 deletions(-) create mode 100644 libethereum/BlockChainSync.cpp create mode 100644 libethereum/BlockChainSync.h diff --git a/libethcore/Common.h b/libethcore/Common.h index 6f23cb0e8..77ec9fa3b 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -100,7 +100,8 @@ enum class ImportResult { Success = 0, UnknownParent, - FutureTime, + FutureTimeKnown, + FutureTimeUnkwnown, AlreadyInChain, AlreadyKnown, Malformed, diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index bd6996a45..b667ba03f 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -372,7 +372,7 @@ pair BlockChain::attemptImport(bytes const& _block, O } catch (FutureTime&) { - return make_pair(ImportResult::FutureTime, make_pair(h256s(), h256s())); + return make_pair(ImportResult::FutureTimeKnown, make_pair(h256s(), h256s())); } catch (Exception& ex) { diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp new file mode 100644 index 000000000..ed43e0786 --- /dev/null +++ b/libethereum/BlockChainSync.cpp @@ -0,0 +1,701 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file EthereumHost.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "BlockChainSync.h" + +#include +#include +#include +#include +#include +#include +#include +#include "BlockChain.h" +#include "TransactionQueue.h" +#include "BlockQueue.h" +#include "EthereumPeer.h" +#include "EthereumHost.h" +#include "DownloadMan.h" +using namespace std; +using namespace dev; +using namespace dev::eth; +using namespace p2p; + + +unsigned const c_chainReorgSize = 30000; + + +BlockChainSync::BlockChainSync(EthereumHost& _host): + m_host(_host) +{ +} + +BlockChainSync::~BlockChainSync() +{ + abortSync(); +} + +DownloadMan const& BlockChainSync::downloadMan() const +{ + return host().downloadMan(); +} + +DownloadMan& BlockChainSync::downloadMan() +{ + return host().downloadMan(); +} + +void BlockChainSync::abortSync() +{ + host().foreachPeer([this](EthereumPeer* _p) { onPeerAborting(_p); return true; }); + downloadMan().resetToChain(h256s()); +} + +void BlockChainSync::onPeerStatus(EthereumPeer*) +{ + +} + +unsigned BlockChainSync::estimateHashes() +{ + BlockInfo block = host().chain().info(); + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t now = time(0); + unsigned blockCount = c_chainReorgSize; + if (lastBlockTime > now) + clog(NetWarn) << "Clock skew? Latest block is in the future"; + else + blockCount += (now - lastBlockTime) / (unsigned)c_durationLimit; + clog(NetAllDetail) << "Estimated hashes: " << blockCount; + return blockCount; +} + +PV60Sync::PV60Sync(EthereumHost& _host): + BlockChainSync(_host) +{ +} + +SyncStatus PV60Sync::status() const +{ + RecursiveGuard l(x_sync); + SyncStatus res; + res.state = m_state; + if (m_state == SyncState::Hashes) + { + res.hashesTotal = m_estimatedHashes; + res.hashesReceived = static_cast(m_syncingNeededBlocks.size()); + res.hashesEstimated = true; + } + else if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks || m_state == SyncState::Waiting) + { + res.blocksTotal = downloadMan().chainSize(); + res.blocksReceived = downloadMan().blocksGot().size(); + } + return res; +} + +void PV60Sync::setState(EthereumPeer* _peer, SyncState _s, bool _isSyncing, bool _needHelp) +{ + bool changedState = (m_state != _s); + m_state = _s; + + if (_isSyncing != (m_syncer == _peer) || (_isSyncing && changedState)) + changeSyncer(_isSyncing ? _peer : nullptr, _needHelp); + else if (_s == SyncState::Idle) + changeSyncer(nullptr, _needHelp); + + assert(!!m_syncer || _s == SyncState::Idle); + + if (!_isSyncing) + { + m_syncingLatestHash = h256(); + m_syncingTotalDifficulty = 0; + m_syncingNeededBlocks.clear(); + } +} + +void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _needHelp) +{ + clog(NetMessageSummary) << "Transition!" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); + + //DEV_INVARIANT_CHECK; + if (m_state == SyncState::Idle && _s != SyncState::Idle) + _peer->m_requireTransactions = true; + + RLPStream s; + if (_s == SyncState::Hashes) + { + if (m_state == SyncState::Idle) + { + if (isSyncing(_peer)) + clog(NetWarn) << "Bad state: not asking for Hashes, yet syncing!"; + + m_syncingLatestHash = _peer->m_latestHash; + m_syncingTotalDifficulty = _peer->m_totalDifficulty; + setState(_peer, _s, true); + _peer->requestHashes(m_syncingLatestHash); + DEV_INVARIANT_CHECK; + return; + } + else if (m_state == SyncState::Hashes) + { + if (!isSyncing(_peer)) + clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; + + setState(_peer, _s, true); + _peer->requestHashes(m_syncingLastReceivedHash); + DEV_INVARIANT_CHECK; + return; + } + } + else if (_s == SyncState::Blocks) + { + if (m_state == SyncState::Hashes) + { + if (!isSyncing(_peer)) + { + clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; + return; + } + if (shouldGrabBlocks(_peer)) + { + clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash << ", was" << host().latestBlockSent() << "]"; + downloadMan().resetToChain(m_syncingNeededBlocks); + } + else + { + clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring."; + m_syncingLatestHash = h256(); + setState(_peer, SyncState::Idle, false); + return; + } + assert (isSyncing(_peer)); + } + // run through into... + if (m_state == SyncState::Idle || m_state == SyncState::Hashes || m_state == SyncState::Blocks) + { + // Looks like it's the best yet for total difficulty. Set to download. + setState(_peer, SyncState::Blocks, isSyncing(_peer), _needHelp); // will kick off other peers to help if available. + requestBlocks(_peer); + DEV_INVARIANT_CHECK; + return; + } + } + else if (_s == SyncState::NewBlocks) + { + if (m_state != SyncState::Idle && m_state != SyncState::NewBlocks) + clog(NetWarn) << "Bad state: Asking new blocks while syncing!"; + else + { + setState(_peer, SyncState::NewBlocks, true, _needHelp); + requestBlocks(_peer); + DEV_INVARIANT_CHECK; + return; + } + } + else if (_s == SyncState::Idle) + { + host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; }); + if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) + { + clog(NetNote) << "Finishing blocks fetch..."; + + // a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry. + if (isSyncing(_peer)) + noteDoneBlocks(_peer, _force); + + // NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary. + _peer->m_sub.doneFetch(); + _peer->setIdle(); + setState(_peer, SyncState::Idle, false); + } + else if (m_state == SyncState::Hashes) + { + clog(NetNote) << "Finishing hashes fetch..."; + setState(_peer, SyncState::Idle, false); + } + // Otherwise it's fine. We don't care if it's Nothing->Nothing. + DEV_INVARIANT_CHECK; + return; + } + + clog(NetWarn) << "Invalid state transition:" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); +} + +void PV60Sync::requestBlocks(EthereumPeer* _peer) +{ + _peer->requestBlocks(); + if (_peer->m_asking != Asking::Blocks) //nothing to download + { + noteDoneBlocks(_peer, false); + if (downloadMan().isComplete()) + transition(_peer, SyncState::Idle); + return; + } +} + +void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 _latestHash, u256 _td) +{ + _peer->m_latestHash = _latestHash; + _peer->m_totalDifficulty = _td; + + if (_peer->m_latestHash) + noteNeedsSyncing(_peer); + + _peer->session()->addNote("sync", string(isSyncing(_peer) ? "ongoing" : "holding") + (needsSyncing(_peer) ? " & needed" : "")); +} + +bool PV60Sync::isSyncing(EthereumPeer* _peer) const +{ + return m_syncer == _peer; +} + +bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const +{ + auto td = _peer->m_totalDifficulty; + auto lh = _peer->m_latestHash; + auto ctd = host().chain().details().totalDifficulty; + + if (m_syncingNeededBlocks.empty()) + return false; + + clog(NetNote) << "Should grab blocks? " << td << "vs" << ctd << ";" << m_syncingNeededBlocks.size() << " blocks, ends" << m_syncingNeededBlocks.back(); + + if (td < ctd || (td == ctd && host().chain().currentHash() == lh)) + return false; + + return true; +} + +void PV60Sync::attemptSync(EthereumPeer* _peer) +{ + if (m_state != SyncState::Idle) + { + clog(NetAllDetail) << "Can't sync with this peer - outstanding asks."; + return; + } + + // if already done this, then ignore. + if (!needsSyncing(_peer)) + { + clog(NetAllDetail) << "Already synced with this peer."; + return; + } + + h256 c = host().chain().currentHash(); + unsigned n = host().chain().number(); + u256 td = host().chain().details().totalDifficulty; + + clog(NetAllDetail) << "Attempt chain-grab? Latest:" << c << ", number:" << n << ", TD:" << td << " versus " << _peer->m_totalDifficulty; + if (td >= _peer->m_totalDifficulty) + { + clog(NetAllDetail) << "No. Our chain is better."; + resetNeedsSyncing(_peer); + transition(_peer, SyncState::Idle); + } + else + { + clog(NetAllDetail) << "Yes. Their chain is better."; + m_estimatedHashes = _peer->m_expectedHashes - c_chainReorgSize; + transition(_peer, SyncState::Hashes); + } +} + +void PV60Sync::noteNeedsSyncing(EthereumPeer* _peer) +{ + // if already downloading hash-chain, ignore. + if (isSyncing()) + { + clog(NetAllDetail) << "Sync in progress: Just set to help out."; + if (m_state == SyncState::Blocks) + _peer->requestBlocks(); + } + else + // otherwise check to see if we should be downloading... + attemptSync(_peer); +} + +void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp) +{ + if (_syncer) + clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId(); + else + clog(NetAllDetail) << "Clearing syncer."; + + m_syncer = _syncer; + if (isSyncing()) + { + if (_needHelp && (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks)) + host().foreachPeer([&](EthereumPeer* _p) + { + clog(NetNote) << "Getting help with downloading blocks"; + if (_p != _syncer && _p->m_asking == Asking::Nothing) + transition(_p, m_state); + return true; + }); + } + else + { + // start grabbing next hash chain if there is one. + host().foreachPeer([this](EthereumPeer* _p) + { + attemptSync(_p); + return !isSyncing(); + }); + if (!isSyncing()) + { + if (m_state != SyncState::Idle) + setState(_syncer, SyncState::Idle); + clog(NetNote) << "No more peers to sync with."; + } + } + assert(!!m_syncer || m_state == SyncState::Idle); +} + +void PV60Sync::noteDoneBlocks(EthereumPeer* _peer, bool _clemency) +{ + resetNeedsSyncing(_peer); + if (downloadMan().isComplete()) + { + // Done our chain-get. + clog(NetNote) << "Chain download complete."; + // 1/100th for each useful block hash. + _peer->addRating(downloadMan().chainSize() / 100); + downloadMan().reset(); + } + else if (isSyncing(_peer)) + { + if (_clemency) + clog(NetNote) << "Chain download failed. Aborted while incomplete."; + else + { + // Done our chain-get. + clog(NetWarn) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished."; + clog(NetWarn) << downloadMan().remaining(); + clog(NetWarn) << "WOULD BAN."; +// m_banned.insert(_peer->session()->id()); // We know who you are! +// _peer->disable("Peer sent hashes but was unable to provide the blocks."); + } + downloadMan().reset(); + } + _peer->m_sub.doneFetch(); +} + +void PV60Sync::onPeerStatus(EthereumPeer* _peer) +{ + RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; + if (_peer->m_genesisHash != host().chain().genesisHash()) + _peer->disable("Invalid genesis hash"); + else if (_peer->m_protocolVersion != host().protocolVersion() && _peer->m_protocolVersion != EthereumHost::c_oldProtocolVersion) + _peer->disable("Invalid protocol version."); + else if (_peer->m_networkId != host().networkId()) + _peer->disable("Invalid network identifier."); + else if (_peer->session()->info().clientVersion.find("/v0.7.0/") != string::npos) + _peer->disable("Blacklisted client version."); + else if (host().isBanned(_peer->session()->id())) + _peer->disable("Peer banned for previous bad behaviour."); + else + { + unsigned estimatedHashes = estimateHashes(); + _peer->m_expectedHashes = estimatedHashes; + setNeedsSyncing(_peer, _peer->m_latestHash, _peer->m_totalDifficulty); + } + DEV_INVARIANT_CHECK; +} + +void PV60Sync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) +{ + RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; + unsigned itemCount = _r.itemCount(); + clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); + + _peer->setIdle(); + if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks) + clog(NetWarn) << "Unexpected Blocks received!"; + + if (itemCount == 0) + { + // Got to this peer's latest block - just give up. + noteDoneBlocks(_peer, false); + if (downloadMan().isComplete()) + transition(_peer, SyncState::Idle); + return; + } + + unsigned success = 0; + unsigned future = 0; + unsigned unknown = 0; + unsigned got = 0; + unsigned repeated = 0; + u256 maxDifficulty = 0; + h256 maxUnknown; + + for (unsigned i = 0; i < itemCount; ++i) + { + auto h = BlockInfo::headerHash(_r[i].data()); + if (_peer->m_sub.noteBlock(h)) + { + _peer->addRating(10); + switch (host().bq().import(_r[i].data(), host().chain())) + { + case ImportResult::Success: + success++; + break; + + case ImportResult::Malformed: + case ImportResult::BadChain: + _peer->disable("Malformed block received."); + return; + + case ImportResult::FutureTimeKnown: + future++; + break; + case ImportResult::AlreadyInChain: + case ImportResult::AlreadyKnown: + got++; + break; + + case ImportResult::FutureTimeUnkwnown: + future++; //Fall through + + case ImportResult::UnknownParent: + { + unknown++; + if (m_state == SyncState::NewBlocks) + { + BlockInfo bi; + bi.populateFromHeader(_r[i][0]); + if (bi.difficulty > maxDifficulty) + { + maxDifficulty = bi.difficulty; + maxUnknown = h; + } + } + break; + } + + default:; + } + } + else + { + _peer->addRating(0); // -1? + repeated++; + } + } + + clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; + + if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) + { + if (downloadMan().isComplete()) + transition(_peer, SyncState::Idle); + else if (!got) + transition(_peer, m_state); + else + noteDoneBlocks(_peer, false); + } + DEV_INVARIANT_CHECK; +} + +void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) +{ + RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; + _peer->setIdle(); + if (!isSyncing(_peer)) + { + clog(NetMessageSummary) << "Ignoring hashes synce not syncing"; + return; + } + if (_hashes.size() == 0) + { + transition(_peer, SyncState::Blocks); + return; + } + unsigned knowns = 0; + unsigned unknowns = 0; + for (unsigned i = 0; i < _hashes.size(); ++i) + { + auto h = _hashes[i]; + auto status = host().bq().blockStatus(h); + if (status == QueueStatus::Importing || status == QueueStatus::Ready || host().chain().isKnown(h)) + { + clog(NetMessageSummary) << "block hash ready:" << h << ". Start blocks download..."; + assert (isSyncing(_peer)); + transition(_peer, SyncState::Blocks); + return; + } + else if (status == QueueStatus::Bad) + { + cwarn << "block hash bad!" << h << ". Bailing..."; + transition(_peer, SyncState::Idle); + return; + } + else if (status == QueueStatus::Unknown) + { + unknowns++; + m_syncingNeededBlocks.push_back(h); + } + else + knowns++; + m_syncingLastReceivedHash = h; + } + clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLastReceivedHash; + if (m_syncingNeededBlocks.size() > _peer->m_expectedHashes) + { + _peer->disable("Too many hashes"); + m_syncingNeededBlocks.clear(); + m_syncingLatestHash = h256(); + transition(_peer, SyncState::Idle); + return; + } + // run through - ask for more. + transition(_peer, SyncState::Hashes); + DEV_INVARIANT_CHECK; +} + + +void PV60Sync::abortSync(EthereumPeer* _peer) +{ + if (isSyncing(_peer)) + { + host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; }); + transition(_peer, SyncState::Idle, true); + } + DEV_INVARIANT_CHECK; +} + +void PV60Sync::onPeerAborting(EthereumPeer* _peer) +{ + abortSync(_peer); + DEV_INVARIANT_CHECK; +} + +void PV60Sync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) +{ + DEV_INVARIANT_CHECK; + RecursiveGuard l(x_sync); + auto h = BlockInfo::headerHash(_r[0].data()); + clog(NetMessageSummary) << "NewBlock: " << h; + + if (_r.itemCount() != 2) + _peer->disable("NewBlock without 2 data fields."); + else + { + switch (host().bq().import(_r[0].data(), host().chain())) + { + case ImportResult::Success: + _peer->addRating(100); + break; + case ImportResult::FutureTimeKnown: + //TODO: Rating dependent on how far in future it is. + break; + + case ImportResult::Malformed: + case ImportResult::BadChain: + _peer->disable("Malformed block received."); + return; + + case ImportResult::AlreadyInChain: + case ImportResult::AlreadyKnown: + break; + + case ImportResult::FutureTimeUnkwnown: + case ImportResult::UnknownParent: + clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; + setNeedsSyncing(_peer, h, _r[1].toInt()); + break; + default:; + } + + DEV_GUARDED(_peer->x_knownBlocks) + _peer->m_knownBlocks.insert(h); + } + DEV_INVARIANT_CHECK; +} + +void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) +{ + RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; + if (isSyncing()) + { + clog(NetMessageSummary) << "Ignoring since we're already downloading."; + return; + } + unsigned knowns = 0; + unsigned unknowns = 0; + for (auto h: _hashes) + { + _peer->addRating(1); + DEV_GUARDED(_peer->x_knownBlocks) + _peer->m_knownBlocks.insert(h); + auto status = host().bq().blockStatus(h); + if (status == QueueStatus::Importing || status == QueueStatus::Ready || host().chain().isKnown(h)) + knowns++; + else if (status == QueueStatus::Bad) + { + cwarn << "block hash bad!" << h << ". Bailing..."; + return; + } + else if (status == QueueStatus::Unknown) + { + unknowns++; + m_syncingNeededBlocks.push_back(h); + } + else + knowns++; + } + clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; + if (unknowns > 0) + { + clog(NetNote) << "Not syncing and new block hash discovered: syncing without help."; + downloadMan().resetToChain(m_syncingNeededBlocks); + transition(_peer, SyncState::NewBlocks, false, false); + } + DEV_INVARIANT_CHECK; +} + +bool PV60Sync::invariants() const +{ + if (m_state == SyncState::Idle && !!m_syncer) + return false; + if (m_state != SyncState::Idle && !m_syncer) + return false; + if (m_state == SyncState::Hashes) + { + bool hashes = false; + host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Hashes) hashes = true; return !hashes; }); + if (!hashes) + return false; + } + if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) + { + bool blocks = false; + host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Blocks) blocks = true; return !blocks; }); + if (!blocks) + return false; + } + return true; +} diff --git a/libethereum/BlockChainSync.h b/libethereum/BlockChainSync.h new file mode 100644 index 000000000..2c3f61de6 --- /dev/null +++ b/libethereum/BlockChainSync.h @@ -0,0 +1,146 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file EthereumHost.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "CommonNet.h" +#include "EthereumPeer.h" //TODO: forward decl +#include "DownloadMan.h" + + +namespace dev +{ + +class RLPStream; + +namespace eth +{ + +class EthereumHost; +class BlockQueue; + +/** + * @brief BlockChain synchronization strategy class + * @doWork Syncs to peers and sends new blocks and transactions. + */ +class BlockChainSync: public HasInvariants +{ +public: + BlockChainSync(EthereumHost& _host); + + /// Will block on network process events. + virtual ~BlockChainSync(); + void abortSync(); + + DownloadMan const& downloadMan() const; + DownloadMan& downloadMan(); + virtual bool isSyncing() const = 0; + virtual void onPeerStatus(EthereumPeer* _peer); ///< Called by peer to report status + virtual void onPeerBlocks(EthereumPeer* _peer, RLP const& _r) = 0; ///< Called by peer once it has new blocks during syn + virtual void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) = 0; ///< Called by peer once it has new blocks + virtual void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; ///< Called by peer once it has new hashes + virtual void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; ///< Called by peer once it has another sequential block of hashes during sync + virtual void onPeerAborting(EthereumPeer* _peer) = 0; ///< Called by peer when it is disconnecting + virtual SyncStatus status() const = 0; + + static char const* stateName(SyncState _s) { return s_stateNames[static_cast(_s)]; } + +private: + static char const* const s_stateNames[static_cast(SyncState::Size)]; + + void setState(SyncState _s); + + bool invariants() const override = 0; + + EthereumHost& m_host; + Handler m_bqRoomAvailable; + HashDownloadMan m_hashMan; + +protected: + + EthereumHost& host() { return m_host; } + EthereumHost const& host() const { return m_host; } + unsigned estimateHashes(); + + mutable RecursiveMutex x_sync; + SyncState m_state = SyncState::Idle; ///< Current sync state + SyncState m_lastActiveState = SyncState::Idle; ///< Saved state before entering waiting queue mode + unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. +}; + +class PV60Sync: public BlockChainSync +{ +public: + + PV60Sync(EthereumHost& _host); + + bool isSyncing() const override { return !!m_syncer; } + void onPeerStatus(EthereumPeer* _peer) override; ///< Called by peer to report status + void onPeerBlocks(EthereumPeer* _peer, RLP const& _r) override; ///< Called by peer once it has new blocks during syn + void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) override; ///< Called by peer once it has new blocks + void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) override; ///< Called by peer once it has new hashes + void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) override; ///< Called by peer once it has another sequential block of hashes during sync + void onPeerAborting(EthereumPeer* _peer) override; ///< Called by peer when it is disconnecting + SyncStatus status() const override; + + void transition(EthereumPeer* _peer, SyncState _s, bool _force = false, bool _needHelp = true); + void resetNeedsSyncing(EthereumPeer* _peer) { setNeedsSyncing(_peer, h256(), 0); } + bool needsSyncing(EthereumPeer* _peer) const { return !!_peer->m_latestHash; } + + void setNeedsSyncing(EthereumPeer* _peer, h256 _latestHash, u256 _td); + bool shouldGrabBlocks(EthereumPeer* _peer) const; + void attemptSync(EthereumPeer* _peer); + void setState(EthereumPeer* _peer, SyncState _s, bool _isSyncing = false, bool _needHelp = false); + bool isSyncing(EthereumPeer* _peer) const; + void noteNeedsSyncing(EthereumPeer* _who); + void changeSyncer(EthereumPeer* _syncer, bool _needHelp); + void noteDoneBlocks(EthereumPeer* _who, bool _clemency); + void abortSync(EthereumPeer* _peer); + void requestBlocks(EthereumPeer* _peer); + + +private: + bool invariants() const override; + + h256s m_knownHashes; ///< List of block hashes we need to download. + + h256s m_syncingNeededBlocks; ///< The blocks that we should download from this peer. + h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer. + h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync. + u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync. + EthereumPeer* m_syncer = nullptr; // TODO: switch to weak_ptr + +}; +} +} diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f142be62e..c8bbfc119 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -229,7 +229,8 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo cblockq << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - return ImportResult::FutureTime; + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + return unknown ? ImportResult::FutureTimeUnkwnown : ImportResult::FutureTimeKnown; } else { diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h index b960c8f3f..35a27ff5e 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -80,10 +80,8 @@ enum class Asking enum class SyncState { Idle, ///< Initial chain sync complete. Waiting for new packets - WaitingQueue, ///< Block downloading paused. Waiting for block queue to process blocks and free space - HashesNegotiate, ///< Waiting for first hashes to arrive - HashesSingle, ///< Locked on and downloading hashes from a single peer - HashesParallel, ///< Downloading hashes from multiple peers over + Waiting, ///< Block downloading paused. Waiting for block queue to process blocks and free space + Hashes, ///< Downloading hashes from multiple peers over Blocks, ///< Downloading blocks NewBlocks, ///< Downloading blocks learned from NewHashes packet diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index e69bfa684..8b8a7c305 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -33,6 +33,8 @@ #include "BlockQueue.h" #include "EthereumPeer.h" #include "DownloadMan.h" +#include "BlockChainSync.h" + using namespace std; using namespace dev; using namespace dev::eth; @@ -41,7 +43,7 @@ using namespace p2p; unsigned const EthereumHost::c_oldProtocolVersion = 60; //TODO: remove this once v61+ is common unsigned const c_chainReorgSize = 30000; -char const* const EthereumHost::s_stateNames[static_cast(SyncState::Size)] = {"Idle", "WaitingQueue", "HashesNegotiate", "HashesSingle", "HashesParallel", "Blocks", "NewBlocks" }; +char const* const EthereumHost::s_stateNames[static_cast(SyncState::Size)] = {"Idle", "Waiting", "Hashes", "Blocks", "NewBlocks" }; EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId): HostCapability(), @@ -51,15 +53,12 @@ EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQu m_bq (_bq), m_networkId (_networkId) { - setState(SyncState::HashesNegotiate); m_latestBlockSent = _ch.currentHash(); - m_hashMan.reset(m_chain.number() + 1); - m_bqRoomAvailable = m_bq.onRoomAvailable([this](){ m_continueSync = true; }); } EthereumHost::~EthereumHost() { - foreachPeer([](EthereumPeer* _p) { _p->abortSync(); }); + //foreachPeer([](EthereumPeer* _p) { _p->abortSync(); }); } bool EthereumHost::ensureInitialised() @@ -79,31 +78,13 @@ bool EthereumHost::ensureInitialised() void EthereumHost::reset() { - foreachPeer([](EthereumPeer* _p) { _p->abortSync(); }); - m_man.resetToChain(h256s()); - m_hashMan.reset(m_chain.number() + 1); - setState(SyncState::HashesNegotiate); - m_syncingLatestHash = h256(); - m_syncingTotalDifficulty = 0; + Guard l(x_sync); + if (m_sync) + m_sync->abortSync(); + m_sync.reset(); + m_latestBlockSent = h256(); m_transactionsSent.clear(); - m_hashes.clear(); -} - -void EthereumHost::resetSyncTo(h256 const& _h) -{ - setState(SyncState::HashesNegotiate); - m_syncingLatestHash = _h; -} - - -void EthereumHost::setState(SyncState _s) -{ - if (m_state != _s) - { - clog(NetAllDetail) << "SyncState changed from " << stateName(m_state) << " to " << stateName(_s); - m_state = _s; - } } void EthereumHost::doWork() @@ -125,14 +106,7 @@ void EthereumHost::doWork() } } - if (m_continueSync) - { - m_continueSync = false; - RecursiveGuard l(x_sync); - continueSync(); - } - - foreachPeer([](EthereumPeer* _p) { _p->tick(); }); + foreachPeer([](EthereumPeer* _p) { _p->tick(); return true; }); // return netChange; // TODO: Figure out what to do with netChange. @@ -174,24 +148,28 @@ void EthereumHost::maintainTransactions() cnote << "Sent" << n << "transactions to " << _p->session()->info().clientVersion; } _p->m_requireTransactions = false; + return true; }); } -void EthereumHost::foreachPeer(std::function const& _f) const +void EthereumHost::foreachPeer(std::function const& _f) const { foreachPeerPtr([&](std::shared_ptr _p) { if (_p) - _f(_p.get()); + return _f(_p.get()); + return true; }); } -void EthereumHost::foreachPeerPtr(std::function)> const& _f) const +void EthereumHost::foreachPeerPtr(std::function)> const& _f) const { for (auto s: peerSessions()) - _f(s.first->cap()); + if (!_f(s.first->cap())) + return; for (auto s: peerSessions(c_oldProtocolVersion)) //TODO: remove once v61+ is common - _f(s.first->cap(c_oldProtocolVersion)); + if (!_f(s.first->cap(c_oldProtocolVersion))) + return; } tuple>, vector>, vector>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) @@ -263,326 +241,50 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash) } } -void EthereumHost::onPeerStatus(EthereumPeer* _peer) +BlockChainSync& EthereumHost::sync() { - RecursiveGuard l(x_sync); - DEV_INVARIANT_CHECK; - if (_peer->m_genesisHash != m_chain.genesisHash()) - _peer->disable("Invalid genesis hash"); - else if (_peer->m_protocolVersion != protocolVersion() && _peer->m_protocolVersion != c_oldProtocolVersion) - _peer->disable("Invalid protocol version."); - else if (_peer->m_networkId != networkId()) - _peer->disable("Invalid network identifier."); - else if (_peer->session()->info().clientVersion.find("/v0.7.0/") != string::npos) - _peer->disable("Blacklisted client version."); - else if (isBanned(_peer->session()->id())) - _peer->disable("Peer banned for previous bad behaviour."); - else + if (m_sync) + return *m_sync; // We only chose sync strategy once + + bool pv61 = false; + foreachPeer([&](EthereumPeer* _p) { - unsigned estimatedHashes = estimateHashes(); - if (_peer->m_protocolVersion == protocolVersion()) - { - if (_peer->m_latestBlockNumber > m_chain.number()) - _peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number(); - if (_peer->m_expectedHashes > estimatedHashes) - _peer->disable("Too many hashes"); - else if (needHashes() && m_hashMan.chainSize() < _peer->m_expectedHashes) - m_hashMan.resetToRange(m_chain.number() + 1, _peer->m_expectedHashes); - } - else - _peer->m_expectedHashes = estimatedHashes; - continueSync(_peer); - } - DEV_INVARIANT_CHECK; + if (_p->m_protocolVersion == protocolVersion()) + pv61 = true; + return !pv61; + }); + m_sync.reset(pv61 ? new PV60Sync(*this) : new PV60Sync(*this)); + return *m_sync; } -unsigned EthereumHost::estimateHashes() +void EthereumHost::onPeerStatus(EthereumPeer* _peer) { - BlockInfo block = m_chain.info(); - time_t lastBlockTime = (block.hash() == m_chain.genesisHash()) ? 1428192000 : (time_t)block.timestamp; - time_t now = time(0); - unsigned blockCount = c_chainReorgSize; - if (lastBlockTime > now) - clog(NetWarn) << "Clock skew? Latest block is in the future"; - else - blockCount += (now - lastBlockTime) / (unsigned)c_durationLimit; - clog(NetAllDetail) << "Estimated hashes: " << blockCount; - return blockCount; + Guard l(x_sync); + sync().onPeerStatus(_peer); } void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) { - RecursiveGuard l(x_sync); - if (_peer->m_syncHashNumber > 0) - _peer->m_syncHashNumber += _hashes.size(); - - _peer->setAsking(Asking::Nothing); - onPeerHashes(_peer, _hashes, false); -} - -void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete) -{ - DEV_INVARIANT_CHECK; - if (_hashes.empty()) - { - _peer->m_hashSub.doneFetch(); - continueSync(); - return; - } - - bool syncByNumber = _peer->m_syncHashNumber; - if (!syncByNumber && !_complete && _peer->m_syncHash != m_syncingLatestHash) - { - // Obsolete hashes, discard - continueSync(_peer); - return; - } - - unsigned knowns = 0; - unsigned unknowns = 0; - h256s neededBlocks; - unsigned firstNumber = _peer->m_syncHashNumber - _hashes.size(); - for (unsigned i = 0; i < _hashes.size(); ++i) - { - _peer->addRating(1); - auto h = _hashes[i]; - auto status = m_bq.blockStatus(h); - if (status == QueueStatus::Importing || status == QueueStatus::Ready || m_chain.isKnown(h)) - { - clog(NetMessageSummary) << "Block hash already known:" << h; - if (!syncByNumber) - { - m_hashes += neededBlocks; - clog(NetMessageSummary) << "Start blocks download..."; - onPeerDoneHashes(_peer, true); - return; - } - } - else if (status == QueueStatus::Bad) - { - cwarn << "block hash bad!" << h << ". Bailing..."; - _peer->setIdle(); - return; - } - else if (status == QueueStatus::Unknown) - { - unknowns++; - neededBlocks.push_back(h); - } - else - knowns++; - - if (!syncByNumber) - m_syncingLatestHash = h; - else - _peer->m_hashSub.noteHash(firstNumber + i, 1); - } - if (syncByNumber) - { - m_man.appendToChain(neededBlocks); // Append to download manager immediatelly - clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; - } - else - { - m_hashes += neededBlocks; // Append to local list - clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLatestHash; - } - if (_complete) - { - clog(NetMessageSummary) << "Start new blocks download..."; - m_syncingLatestHash = h256(); - setState(SyncState::NewBlocks); - m_man.resetToChain(m_hashes); - m_hashes.clear(); - m_hashMan.reset(m_chain.number() + 1); - continueSync(_peer); - } - else if (syncByNumber && m_hashMan.isComplete()) - { - // Done our chain-get. - clog(NetNote) << "Hashes download complete."; - onPeerDoneHashes(_peer, false); - } - else if (m_hashes.size() > _peer->m_expectedHashes) - { - _peer->disable("Too many hashes"); - m_hashes.clear(); - m_syncingLatestHash = h256(); - setState(SyncState::HashesNegotiate); - continueSync(); ///Try with some other peer, keep the chain - } - else - continueSync(_peer); /// Grab next hashes - DEV_INVARIANT_CHECK; -} - -void EthereumHost::onPeerDoneHashes(EthereumPeer* _peer, bool _localChain) -{ - assert(_peer->m_asking == Asking::Nothing); - m_syncingLatestHash = h256(); - setState(SyncState::Blocks); - if (_peer->m_protocolVersion != protocolVersion() || _localChain) - { - m_man.resetToChain(m_hashes); - _peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers? - } - m_hashMan.reset(m_chain.number() + 1); - m_hashes.clear(); - continueSync(); + Guard l(x_sync); + sync().onPeerHashes(_peer, _hashes); } void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) { - RecursiveGuard l(x_sync); - DEV_INVARIANT_CHECK; - _peer->setAsking(Asking::Nothing); - unsigned itemCount = _r.itemCount(); - clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); - - if (itemCount == 0) - { - // Got to this peer's latest block - just give up. - clog(NetNote) << "Finishing blocks fetch..."; - // NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary. - _peer->m_sub.doneFetch(); - _peer->setIdle(); - return; - } - - unsigned success = 0; - unsigned future = 0; - unsigned unknown = 0; - unsigned got = 0; - unsigned repeated = 0; - h256 lastUnknown; - - for (unsigned i = 0; i < itemCount; ++i) - { - auto h = BlockInfo::headerHash(_r[i].data()); - if (_peer->m_sub.noteBlock(h)) - { - _peer->addRating(10); - switch (m_bq.import(_r[i].data(), m_chain)) - { - case ImportResult::Success: - success++; - break; - - case ImportResult::Malformed: - case ImportResult::BadChain: - _peer->disable("Malformed block received."); - return; - - case ImportResult::FutureTime: - future++; - break; - - case ImportResult::AlreadyInChain: - case ImportResult::AlreadyKnown: - got++; - break; - - case ImportResult::UnknownParent: - lastUnknown = h; - unknown++; - break; - - default:; - } - } - else - { - _peer->addRating(0); // -1? - repeated++; - } - } - - clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; - - if (m_state == SyncState::NewBlocks && unknown > 0) - { - _peer->m_latestHash = lastUnknown; - resetSyncTo(lastUnknown); - } - - continueSync(_peer); - DEV_INVARIANT_CHECK; + Guard l(x_sync); + sync().onPeerBlocks(_peer, _r); } void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { - RecursiveGuard l(x_sync); - DEV_INVARIANT_CHECK; - if (isSyncing() || _peer->isConversing()) - { - clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; - return; - } - clog(NetNote) << "New block hash discovered: syncing without help."; - _peer->m_syncHashNumber = 0; - onPeerHashes(_peer, _hashes, true); - DEV_INVARIANT_CHECK; + Guard l(x_sync); + sync().onPeerNewHashes(_peer, _hashes); } void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { - RecursiveGuard l(x_sync); - DEV_INVARIANT_CHECK; - if ((isSyncing() || _peer->isConversing()) && m_state != SyncState::NewBlocks) - { - clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; - return; - } - auto h = BlockInfo::headerHash(_r[0].data()); - clog(NetMessageSummary) << "NewBlock: " << h; - - if (_r.itemCount() != 2) - _peer->disable("NewBlock without 2 data fields."); - else - { - bool sync = false; - switch (m_bq.import(_r[0].data(), m_chain)) - { - case ImportResult::Success: - _peer->addRating(100); - break; - case ImportResult::FutureTime: - //TODO: Rating dependent on how far in future it is. - break; - - case ImportResult::Malformed: - case ImportResult::BadChain: - _peer->disable("Malformed block received."); - return; - - case ImportResult::AlreadyInChain: - case ImportResult::AlreadyKnown: - break; - - case ImportResult::UnknownParent: - if (h) - { - u256 difficulty = _r[1].toInt(); - if (m_syncingTotalDifficulty < difficulty) - { - clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; - _peer->m_latestHash = h; - _peer->m_totalDifficulty = difficulty; - resetSyncTo(h);; - sync = true; - } - } - break; - default:; - } - - DEV_GUARDED(_peer->x_knownBlocks) - _peer->m_knownBlocks.insert(h); - - if (sync) - continueSync(); - } - DEV_INVARIANT_CHECK; + Guard l(x_sync); + sync().onPeerNewBlock(_peer, _r); } void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) @@ -615,202 +317,28 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerAborting(EthereumPeer* _peer) { - RecursiveGuard l(x_sync); - if (_peer->isConversing()) - { - _peer->setIdle(); - if (_peer->isCriticalSyncing()) - _peer->setRude(); - continueSync(); - } -} - -void EthereumHost::continueSync() -{ - if (m_state == SyncState::WaitingQueue) - setState(m_lastActiveState); - clog(NetAllDetail) << "Continuing sync for all peers"; - foreachPeer([&](EthereumPeer* _p) - { - if (_p->m_asking == Asking::Nothing) - continueSync(_p); - }); -} - -void EthereumHost::continueSync(EthereumPeer* _peer) -{ - DEV_INVARIANT_CHECK; - assert(_peer->m_asking == Asking::Nothing); - bool otherPeerV60Sync = false; - bool otherPeerV61Sync = false; - if (needHashes()) - { - if (!peerShouldGrabChain(_peer)) - { - _peer->setIdle(); - return; - } - - foreachPeer([&](EthereumPeer* _p) - { - if (_p != _peer && _p->m_asking == Asking::Hashes) - { - if (_p->m_protocolVersion != protocolVersion()) - otherPeerV60Sync = true; // Already have a peer downloading hash chain with old protocol, do nothing - else - otherPeerV61Sync = true; // Already have a peer downloading hash chain with V61+ protocol, join if supported - } - }); - if (otherPeerV60Sync && !m_hashes.empty()) - { - /// Downloading from other peer with v60 protocol, nothing else we can do - _peer->setIdle(); - return; - } - if (otherPeerV61Sync && _peer->m_protocolVersion != protocolVersion()) - { - /// Downloading from other peer with v61+ protocol which this peer does not support, - _peer->setIdle(); - return; - } - if (_peer->m_protocolVersion == protocolVersion() && !m_hashMan.isComplete()) - { - setState(SyncState::HashesParallel); - _peer->requestHashes(); /// v61+ and not catching up to a particular hash - } - else - { - // Restart/continue sync in single peer mode - if (!m_syncingLatestHash) - { - m_syncingLatestHash =_peer->m_latestHash; - m_syncingTotalDifficulty = _peer->m_totalDifficulty; - } - if (_peer->m_totalDifficulty >= m_syncingTotalDifficulty) - { - _peer->requestHashes(m_syncingLatestHash); - setState(SyncState::HashesSingle); - m_estimatedHashes = _peer->m_expectedHashes - (_peer->m_protocolVersion == protocolVersion() ? 0 : c_chainReorgSize); - } - else - _peer->setIdle(); - } - } - else if (needBlocks()) - { - if (m_man.isComplete()) - { - // Done our chain-get. - setState(SyncState::Idle); - clog(NetNote) << "Chain download complete."; - // 1/100th for each useful block hash. - _peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers? - m_man.reset(); - _peer->setIdle(); - return; - } - else if (peerCanHelp(_peer)) - { - // Check block queue status - if (m_bq.unknownFull()) - { - clog(NetWarn) << "Too many unknown blocks, restarting sync"; - m_bq.clear(); - reset(); - continueSync(); - } - else if (m_bq.knownFull()) - { - clog(NetAllDetail) << "Waiting for block queue before downloading blocks"; - m_lastActiveState = m_state; - setState(SyncState::WaitingQueue); - _peer->setIdle(); - } - else - _peer->requestBlocks(); - } - } - else - _peer->setIdle(); - DEV_INVARIANT_CHECK; -} - -bool EthereumHost::peerCanHelp(EthereumPeer* _peer) const -{ - (void)_peer; - return true; -} - -bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const -{ - // this is only good for deciding whether to go ahead and grab a particular peer's hash chain, - // yet it's being used in determining whether to allow a peer help with downloading an existing - // chain of blocks. - auto td = _peer->m_totalDifficulty; - auto lh = m_syncingLatestHash; - auto ctd = m_chain.details().totalDifficulty; - - clog(NetAllDetail) << "Should grab blocks? " << td << "vs" << ctd; - if (td < ctd || (td == ctd && m_chain.currentHash() == lh)) - return false; - return true; -} - -bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const -{ - h256 c = m_chain.currentHash(); - unsigned n = m_chain.number(); - u256 td = m_chain.details().totalDifficulty; - - clog(NetAllDetail) << "Attempt chain-grab? Latest:" << c << ", number:" << n << ", TD:" << td << " versus " << _peer->m_totalDifficulty; - if (td >= _peer->m_totalDifficulty) - { - clog(NetAllDetail) << "No. Our chain is better."; - return false; - } - else - { - clog(NetAllDetail) << "Yes. Their chain is better."; - return true; - } + Guard l(x_sync); + if (m_sync) + m_sync->onPeerAborting(_peer); } bool EthereumHost::isSyncing() const { - return m_state != SyncState::Idle; + Guard l(x_sync); + if (!m_sync) + return false; + return m_sync->isSyncing(); } SyncStatus EthereumHost::status() const { - RecursiveGuard l(x_sync); - SyncStatus res; - res.state = m_state; - if (m_state == SyncState::HashesParallel) - { - res.hashesReceived = m_hashMan.hashesGot().size(); - res.hashesTotal = m_hashMan.chainSize(); - } - else if (m_state == SyncState::HashesSingle) - { - res.hashesTotal = m_estimatedHashes; - res.hashesReceived = static_cast(m_hashes.size()); - res.hashesEstimated = true; - } - else if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks || m_state == SyncState::WaitingQueue) - { - res.blocksTotal = m_man.chainSize(); - res.blocksReceived = m_man.blocksGot().size(); - } - return res; + Guard l(x_sync); + if (!m_sync) + return SyncStatus(); + return m_sync->status(); } - bool EthereumHost::invariants() const { - if (m_state == SyncState::HashesNegotiate && !m_hashes.empty()) - return false; - if (needBlocks() && (m_syncingLatestHash || !m_hashes.empty())) - return false; - return true; } diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 098d893ee..aed35c192 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -48,6 +48,7 @@ namespace eth class TransactionQueue; class BlockQueue; +class BlockChainSync; /** * @brief The EthereumHost class @@ -57,7 +58,6 @@ class BlockQueue; class EthereumHost: public p2p::HostCapability, Worker, HasInvariants { public: - /// Start server, but don't listen. EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId); @@ -71,50 +71,42 @@ public: void reset(); DownloadMan const& downloadMan() const { return m_man; } + DownloadMan& downloadMan() { return m_man; } bool isSyncing() const; bool isBanned(p2p::NodeId const& _id) const { return !!m_banned.count(_id); } void noteNewTransactions() { m_newTransactions = true; } void noteNewBlocks() { m_newBlocks = true; } - void onPeerStatus(EthereumPeer* _peer); ///< Called by peer to report status - void onPeerBlocks(EthereumPeer* _peer, RLP const& _r); ///< Called by peer once it has new blocks during syn - void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); ///< Called by peer once it has new blocks - void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has new hashes - void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has another sequential block of hashes during sync - void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); ///< Called by peer when it has new transactions - void onPeerAborting(EthereumPeer* _peer); ///< Called by peer when it is disconnecting - - DownloadMan& downloadMan() { return m_man; } - HashDownloadMan& hashDownloadMan() { return m_hashMan; } - BlockChain const& chain() { return m_chain; } + BlockChain const& chain() const { return m_chain; } + BlockQueue& bq() { return m_bq; } SyncStatus status() const; + h256 latestBlockSent() { return m_latestBlockSent; } static char const* stateName(SyncState _s) { return s_stateNames[static_cast(_s)]; } static unsigned const c_oldProtocolVersion; + void foreachPeerPtr(std::function)> const& _f) const; + void foreachPeer(std::function const& _f) const; + + void onPeerStatus(EthereumPeer* _peer); + void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); + void onPeerBlocks(EthereumPeer* _peer, RLP const& _r); + void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); + void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); + void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); + void onPeerAborting(EthereumPeer* _peer); private: static char const* const s_stateNames[static_cast(SyncState::Size)]; std::tuple>, std::vector>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); - void foreachPeerPtr(std::function)> const& _f) const; - void foreachPeer(std::function const& _f) const; - void resetSyncTo(h256 const& _h); - bool needHashes() const { return m_state == SyncState::HashesNegotiate || m_state == SyncState::HashesSingle || m_state == SyncState::HashesParallel; } - bool needBlocks() const { return m_state == SyncState::Blocks || m_state == SyncState::NewBlocks; } - /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. void doWork(); void maintainTransactions(); void maintainBlocks(h256 const& _currentBlock); - /// Get a bunch of needed blocks. - /// Removes them from our list of needed blocks. - /// @returns empty if there's no more blocks left to fetch, otherwise the blocks to fetch. - h256Hash neededBlocks(h256Hash const& _exclude); - /// Check to see if the network peer-state initialisation has happened. bool isInitialised() const { return (bool)m_latestBlockSent; } @@ -124,29 +116,16 @@ private: virtual void onStarting() { startWorking(); } virtual void onStopping() { stopWorking(); } - void continueSync(); /// Find something to do for all peers - void continueSync(EthereumPeer* _peer); /// Find some work to do for a peer - void onPeerDoneHashes(EthereumPeer* _peer, bool _new); /// Called when done downloading hashes from peer - void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete); - bool peerShouldGrabBlocks(EthereumPeer* _peer) const; - bool peerShouldGrabChain(EthereumPeer* _peer) const; - bool peerCanHelp(EthereumPeer* _peer) const; - unsigned estimateHashes(); - void estimatePeerHashes(EthereumPeer* _peer); - void setState(SyncState _s); + BlockChainSync& sync(); bool invariants() const override; BlockChain const& m_chain; TransactionQueue& m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. BlockQueue& m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). - Handler m_bqRoomAvailable; u256 m_networkId; - DownloadMan m_man; - HashDownloadMan m_hashMan; - h256 m_latestBlockSent; h256Hash m_transactionsSent; @@ -155,14 +134,9 @@ private: bool m_newTransactions = false; bool m_newBlocks = false; - mutable RecursiveMutex x_sync; - SyncState m_state = SyncState::Idle; ///< Current sync state - SyncState m_lastActiveState = SyncState::Idle; ///< Saved state before entering waiting queue mode - h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync. - u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync. - h256s m_hashes; ///< List of hashes with unknown block numbers. Used for PV60 chain downloading and catching up to a particular unknown - unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. - bool m_continueSync = false; ///< True when the block queue has processed a block; we should restart grabbing blocks. + mutable Mutex x_sync; + DownloadMan m_man; + std::unique_ptr m_sync; }; } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 7a30f1ad9..8aca62b9a 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -30,6 +30,8 @@ #include "EthereumHost.h" #include "TransactionQueue.h" #include "BlockQueue.h" +#include "BlockChainSync.h" + using namespace std; using namespace dev; using namespace dev::eth; @@ -38,7 +40,6 @@ using namespace p2p; EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap): Capability(_s, _h, _i), m_sub(host()->downloadMan()), - m_hashSub(host()->hashDownloadMan()), m_peerCapabilityVersion(_cap.second) { session()->addNote("manners", isRude() ? "RUDE" : "nice"); @@ -91,8 +92,6 @@ string toString(Asking _a) void EthereumPeer::setIdle() { - m_sub.doneFetch(); - m_hashSub.doneFetch(); setAsking(Asking::Nothing); } @@ -113,14 +112,14 @@ void EthereumPeer::requestStatus() sealAndSend(s); } -void EthereumPeer::requestHashes() +void EthereumPeer::requestHashes(u256 _number, unsigned _count) { assert(m_asking == Asking::Nothing); - m_syncHashNumber = m_hashSub.nextFetch(c_maxHashesAsk); + m_syncHashNumber = _number; m_syncHash = h256(); setAsking(Asking::Hashes); RLPStream s; - prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << c_maxHashesAsk; + prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << _count; clog(NetMessageDetail) << "Requesting block hashes for numbers " << m_syncHashNumber << "-" << m_syncHashNumber + c_maxHashesAsk - 1; sealAndSend(s); } diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index a12b7a197..2ffbe9101 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -50,6 +50,9 @@ namespace eth class EthereumPeer: public p2p::Capability { friend class EthereumHost; //TODO: remove this + friend class BlockChainSync; //TODO: remove this + friend class PV60Sync; //TODO: remove this + friend class PV61Sync; //TODO: remove this public: /// Basic constructor. @@ -73,8 +76,8 @@ public: /// Abort sync and reset fetch void setIdle(); - /// Request hashes. Uses hash download manager to get hash number. v61+ protocol version only - void requestHashes(); + /// Request hashes by number. v61+ protocol version only + void requestHashes(u256 _number, unsigned _count); /// Request hashes for given parent hash. void requestHashes(h256 const& _lastHash); @@ -135,18 +138,19 @@ private: h256 m_genesisHash; ///< Peer's genesis hash u256 m_latestBlockNumber; ///< Number of the latest block this peer has + /// This is built as we ask for hashes. Once no more hashes are given, we present this to the /// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks. + h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer. + h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync. + u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync. unsigned m_expectedHashes = 0; ///< Estimated upper bound of hashes to expect from this peer. - unsigned m_syncHashNumber = 0; ///< Number of latest hash we sync to (PV61+) + u256 m_syncHashNumber = 0; ///< Number of latest hash we sync to (PV61+) h256 m_syncHash; ///< Latest hash we sync to (PV60) /// Once we're asking for blocks, this becomes in use. DownloadSub m_sub; - /// Once we're asking for hashes, this becomes in use. - HashDownloadSub m_hashSub; - u256 m_peerCapabilityVersion; ///< Protocol version this peer supports received as capability /// Have we received a GetTransactions packet that we haven't yet answered? bool m_requireTransactions = false; From 07b811ebfa47c680a8b15e8631985e65c8e9e3b3 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 17 Jun 2015 11:45:36 +0200 Subject: [PATCH 044/103] basic AES tests --- libdevcrypto/AES.h | 2 + test/libdevcrypto/AES.cpp | 92 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 test/libdevcrypto/AES.cpp diff --git a/libdevcrypto/AES.h b/libdevcrypto/AES.h index 32d1880dc..6aaed6fad 100644 --- a/libdevcrypto/AES.h +++ b/libdevcrypto/AES.h @@ -75,6 +75,8 @@ public: /// Adjust mac interval. Next mac will be xored with value. void adjustInterval(unsigned _interval) { m_macInterval = _interval; } + + unsigned getMacInterval() { return m_macInterval;} private: AuthenticatedStream(AuthenticatedStream const&) = delete; diff --git a/test/libdevcrypto/AES.cpp b/test/libdevcrypto/AES.cpp new file mode 100644 index 000000000..5742b882e --- /dev/null +++ b/test/libdevcrypto/AES.cpp @@ -0,0 +1,92 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file MemTrie.h + * @author Christoph Jentzsch + * @date 2015 + */ + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace dev; + +BOOST_AUTO_TEST_SUITE(AES) + +BOOST_AUTO_TEST_CASE(AesDecrypt) +{ + cout << "AesDecrypt" << endl; + bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); + KeyPair kp(sha3(aesDecrypt(&seed, "test"))); + BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") == kp.address()); +} + +BOOST_AUTO_TEST_CASE(AesDecryptWrongSeed) +{ + cout << "AesDecryptWrongSeed" << endl; + bytes seed = fromHex("badaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); + KeyPair kp(sha3(aesDecrypt(&seed, "test"))); + BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); +} + +BOOST_AUTO_TEST_CASE(AesDecryptWrongPassword) +{ + cout << "AesDecryptWrongPassword" << endl; + bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); + KeyPair kp(sha3(aesDecrypt(&seed, "badtest"))); + BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address()); +} + +BOOST_AUTO_TEST_CASE(AesDecryptFailInvalidSeed) +{ + cout << "AesDecryptFailInvalidSeed" << endl; + bytes seed = fromHex("xdbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621"); + BOOST_CHECK(bytes() == aesDecrypt(&seed, "test")); +} + +BOOST_AUTO_TEST_CASE(AesDecryptFailInvalidSeedSize) +{ + cout << "AesDecryptFailInvalidSeedSize" << endl; + bytes seed = fromHex("000102030405060708090a0b0c0d0e0f"); + BOOST_CHECK(bytes() == aesDecrypt(&seed, "test")); +} + +BOOST_AUTO_TEST_CASE(AesDecryptFailInvalidSeed2) +{ + cout << "AesDecryptFailInvalidSeed2" << endl; + bytes seed = fromHex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"); + BOOST_CHECK(bytes() == aesDecrypt(&seed, "test")); +} +BOOST_AUTO_TEST_CASE(AuthenticatedStreamConstructor) +{ + cout << "AuthenticatedStreamConstructor" << endl; + + Secret const sec("test"); + crypto::aes::AuthenticatedStream as(crypto::aes::Encrypt, sec, 0); + BOOST_CHECK(as.getMacInterval() == 0); + as.adjustInterval(1); + BOOST_CHECK(as.getMacInterval() == 1); + crypto::aes::AuthenticatedStream as_mac(crypto::aes::Encrypt, h128(), h128(), 42); + BOOST_CHECK(as_mac.getMacInterval() == 42); +} + +BOOST_AUTO_TEST_SUITE_END() + From d420a1c025389fee00559ac5573758451f79fa74 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 17 Jun 2015 11:48:35 +0200 Subject: [PATCH 045/103] style --- test/libethereum/blockchain.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 2dc30c6ba..de28d30ff 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -581,11 +581,9 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector } updatePoW(uncleBlockFromFields); - if (overwrite == "nonce" || overwrite == "mixHash") - { - uncleBlockFromFields.nonce = overwrite == "nonce" ? Nonce(uncleHeaderObj["nonce"].get_str()) : uncleBlockFromFields.nonce; - uncleBlockFromFields.mixHash = overwrite == "mixHash" ? h256(uncleHeaderObj["mixHash"].get_str()) : uncleBlockFromFields.mixHash; - } + + uncleBlockFromFields.nonce = overwrite == "nonce" ? Nonce(uncleHeaderObj["nonce"].get_str()) : uncleBlockFromFields.nonce; + uncleBlockFromFields.mixHash = overwrite == "mixHash" ? h256(uncleHeaderObj["mixHash"].get_str()) : uncleBlockFromFields.mixHash; writeBlockHeaderToJson(uncleHeaderObj, uncleBlockFromFields); From 83cc17f240c02eab9bf4cbf4436e6ab356c11693 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 17 Jun 2015 12:22:04 +0200 Subject: [PATCH 046/103] update file name in description --- test/libdevcrypto/AES.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libdevcrypto/AES.cpp b/test/libdevcrypto/AES.cpp index 5742b882e..071f1509c 100644 --- a/test/libdevcrypto/AES.cpp +++ b/test/libdevcrypto/AES.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file MemTrie.h +/** @file AES.cpp * @author Christoph Jentzsch * @date 2015 */ From a2e06448e3db239d4dbca9d338fc8b7bd3c451ee Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 17 Jun 2015 13:00:44 +0200 Subject: [PATCH 047/103] small changes --- mix/ContractCallDataEncoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index e67ce9cea..1b713b82b 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -45,12 +45,12 @@ bytes ContractCallDataEncoder::encodedData() for (auto const& p: m_dynamicOffsetMap) { vector_ref offsetRef(m_dynamicData.data() + p.first, 32); - toBigEndian>(p.second + headerSize, offsetRef); //add header size minus signature hash + toBigEndian(p.second + headerSize, offsetRef); //add header size minus signature hash } for (auto const& p: m_staticOffsetMap) { vector_ref offsetRef(r.data() + p.first, 32); - toBigEndian>(p.second + headerSize, offsetRef); //add header size minus signature hash + toBigEndian(p.second + headerSize, offsetRef); //add header size minus signature hash } if (m_dynamicData.size() > 0) r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end()); From 8198665eca2d338c7484b5cfeef9e976fc830b28 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Wed, 17 Jun 2015 13:10:10 +0200 Subject: [PATCH 048/103] minor improvements --- libwhisper/BloomFilter.cpp | 9 +++------ libwhisper/Common.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp index c189ee912..cff69c664 100644 --- a/libwhisper/BloomFilter.cpp +++ b/libwhisper/BloomFilter.cpp @@ -35,11 +35,8 @@ void TopicBloomFilter::addRaw(AbridgedTopic const& _h) { if (m_refCounter[i] != numeric_limits::max()) m_refCounter[i]++; - //else: overflow - - // in order to encounter overflow, you have to set at least 65536 filters simultaneously. - // even then, the problem will only arise after at least 65536 filters will be be removed. - // we assume, it will never happen. + else + BOOST_THROW_EXCEPTION(Overflow()); } } @@ -52,7 +49,7 @@ void TopicBloomFilter::removeRaw(AbridgedTopic const& _h) m_refCounter[i]--; if (!m_refCounter[i]) - (*this)[i/8] &= ~c_mask[i%8]; + (*this)[i / 8] &= ~c_mask[i % 8]; } } diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 5dc267fcf..7f5b8ed06 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -38,7 +38,7 @@ AbridgedTopics dev::shh::abridge(Topics const& _topics) { AbridgedTopics ret; ret.reserve(_topics.size()); - for (auto const& t : _topics) + for (auto const& t: _topics) ret.push_back(abridge(t)); return ret; } @@ -87,10 +87,10 @@ bool TopicFilter::matches(Envelope const& _e) const TopicFilter::TopicFilter(RLP const& _r) { - for (RLP i: _r) + for (RLP const& i: _r) { m_topicMasks.push_back(TopicMask()); - for (RLP j: i) + for (RLP const& j: i) m_topicMasks.back().push_back(j.toPair, FixedHash<4>>()); } } @@ -99,7 +99,7 @@ AbridgedTopic TopicFilter::exportBloom() const { AbridgedTopic ret; for (TopicMask const& t: m_topicMasks) - for (auto i: t) + for (auto const& i: t) ret |= i.first.template bloomPart(); return ret; From 52bc8a6c5ca8e70061feaa060e85269322f30aeb Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 17 Jun 2015 14:05:40 +0200 Subject: [PATCH 049/103] small changes --- mix/ContractCallDataEncoder.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 1b713b82b..a1aae3f79 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -98,7 +98,6 @@ void ContractCallDataEncoder::encodeArray(QJsonArray const& _array, QList _ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& _type) { QStringList strList; - vector dim; if (_type.array) { QList dim = extractDimension(_type. name); From 536bd36185323109524f84ddf5d333e786c05cfb Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Jun 2015 12:01:39 +0200 Subject: [PATCH 050/103] Accessors for strings. --- libsolidity/AST.cpp | 10 +-- libsolidity/ArrayUtils.cpp | 56 ++++++++-------- libsolidity/Compiler.cpp | 40 ++++++++---- libsolidity/CompilerUtils.cpp | 57 +++++++++++------ libsolidity/CompilerUtils.h | 5 +- libsolidity/ExpressionCompiler.cpp | 34 ++++++---- libsolidity/NameAndTypeResolver.cpp | 8 +-- libsolidity/Types.cpp | 62 ++++++++++-------- libsolidity/Types.h | 35 +++++----- test/libsolidity/SolidityEndToEndTest.cpp | 78 +++++++++++++++++++++++ test/libsolidity/SolidityTypes.cpp | 14 ++-- 11 files changed, 267 insertions(+), 132 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index dbeec858e..6d6a13cff 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -919,7 +919,7 @@ void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes) { auto const& arrayType(dynamic_cast(type)); m_isLValue = (*m_memberName == "length" && - arrayType.location() != ReferenceType::Location::CallData && arrayType.isDynamicallySized()); + arrayType.location() != DataLocation::CallData && arrayType.isDynamicallySized()); } else m_isLValue = false; @@ -942,7 +942,7 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) m_type = make_shared(1); else m_type = type.getBaseType(); - m_isLValue = type.location() != ReferenceType::Location::CallData; + m_isLValue = type.location() != DataLocation::CallData; break; } case Type::Category::Mapping: @@ -959,7 +959,7 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) { TypeType const& type = dynamic_cast(*m_base->getType()); if (!m_index) - m_type = make_shared(make_shared(ReferenceType::Location::Memory, type.getActualType())); + m_type = make_shared(make_shared(DataLocation::Memory, type.getActualType())); else { m_index->checkTypeRequirements(nullptr); @@ -967,7 +967,9 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) if (!length) BOOST_THROW_EXCEPTION(m_index->createTypeError("Integer constant expected.")); m_type = make_shared(make_shared( - ReferenceType::Location::Memory, type.getActualType(), length->literalValue(nullptr))); + DataLocation::Memory, type.getActualType(), + length->literalValue(nullptr) + )); } break; } diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index b770b815c..43ffff0b6 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -38,10 +38,10 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // need to leave "target_ref target_byte_off" on the stack at the end // stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top) - solAssert(_targetType.location() == ReferenceType::Location::Storage, ""); + solAssert(_targetType.location() == DataLocation::Storage, ""); solAssert( - _sourceType.location() == ReferenceType::Location::CallData || - _sourceType.location() == ReferenceType::Location::Storage, + _sourceType.location() == DataLocation::CallData || + _sourceType.location() == DataLocation::Storage, "Given array location not implemented." ); @@ -51,7 +51,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // TODO unroll loop for small sizes - bool sourceIsStorage = _sourceType.location() == ReferenceType::Location::Storage; + bool sourceIsStorage = _sourceType.location() == DataLocation::Storage; bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType; bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->getStorageBytes() <= 16; bool haveByteOffsetTarget = !directCopy && targetBaseType->getStorageBytes() <= 16; @@ -69,7 +69,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons m_context << eth::Instruction::POP; // stack: target_ref source_ref [source_length] // retrieve source length - if (_sourceType.location() != ReferenceType::Location::CallData || !_sourceType.isDynamicallySized()) + if (_sourceType.location() != DataLocation::CallData || !_sourceType.isDynamicallySized()) retrieveLength(_sourceType); // otherwise, length is already there // stack: target_ref source_ref source_length m_context << eth::Instruction::DUP3; @@ -82,7 +82,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons if (sourceBaseType->getCategory() == Type::Category::Mapping) { solAssert(targetBaseType->getCategory() == Type::Category::Mapping, ""); - solAssert(_sourceType.location() == ReferenceType::Location::Storage, ""); + solAssert(_sourceType.location() == DataLocation::Storage, ""); // nothing to copy m_context << eth::Instruction::POP << eth::Instruction::POP @@ -106,7 +106,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons eth::AssemblyItem copyLoopEndWithoutByteOffset = m_context.newTag(); m_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset); - if (_sourceType.location() == ReferenceType::Location::Storage && _sourceType.isDynamicallySized()) + if (_sourceType.location() == DataLocation::Storage && _sourceType.isDynamicallySized()) CompilerUtils(m_context).computeHashStatic(); // stack: target_ref target_data_end source_length target_data_pos source_data_pos m_context << eth::Instruction::SWAP2; @@ -155,7 +155,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // checking is easier. // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] m_context << eth::dupInstruction(3 + byteOffsetSize); - if (_sourceType.location() == ReferenceType::Location::Storage) + if (_sourceType.location() == DataLocation::Storage) { if (haveByteOffsetSource) m_context << eth::Instruction::DUP2; @@ -231,7 +231,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons void ArrayUtils::clearArray(ArrayType const& _type) const { unsigned stackHeightStart = m_context.getStackHeight(); - solAssert(_type.location() == ReferenceType::Location::Storage, ""); + solAssert(_type.location() == DataLocation::Storage, ""); if (_type.getBaseType()->getStorageBytes() < 32) { solAssert(_type.getBaseType()->isValueType(), "Invalid storage size for non-value type."); @@ -286,7 +286,7 @@ void ArrayUtils::clearArray(ArrayType const& _type) const void ArrayUtils::clearDynamicArray(ArrayType const& _type) const { - solAssert(_type.location() == ReferenceType::Location::Storage, ""); + solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.isDynamicallySized(), ""); unsigned stackHeightStart = m_context.getStackHeight(); @@ -314,7 +314,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const void ArrayUtils::resizeDynamicArray(const ArrayType& _type) const { - solAssert(_type.location() == ReferenceType::Location::Storage, ""); + solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.isDynamicallySized(), ""); if (!_type.isByteArray() && _type.getBaseType()->getStorageBytes() < 32) solAssert(_type.getBaseType()->isValueType(), "Invalid storage size for non-value type."); @@ -399,7 +399,7 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) const { - if (_arrayType.location() == ReferenceType::Location::Storage) + if (_arrayType.location() == DataLocation::Storage) { if (_arrayType.getBaseType()->getStorageSize() <= 1) { @@ -437,13 +437,13 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const m_context << eth::Instruction::DUP1; switch (_arrayType.location()) { - case ReferenceType::Location::CallData: + case DataLocation::CallData: // length is stored on the stack break; - case ReferenceType::Location::Memory: + case DataLocation::Memory: m_context << eth::Instruction::MLOAD; break; - case ReferenceType::Location::Storage: + case DataLocation::Storage: m_context << eth::Instruction::SLOAD; break; } @@ -452,16 +452,16 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const void ArrayUtils::accessIndex(ArrayType const& _arrayType) const { - ReferenceType::Location location = _arrayType.location(); + DataLocation location = _arrayType.location(); eth::Instruction load = - location == ReferenceType::Location::Storage ? eth::Instruction::SLOAD : - location == ReferenceType::Location::Memory ? eth::Instruction::MLOAD : + location == DataLocation::Storage ? eth::Instruction::SLOAD : + location == DataLocation::Memory ? eth::Instruction::MLOAD : eth::Instruction::CALLDATALOAD; // retrieve length if (!_arrayType.isDynamicallySized()) m_context << _arrayType.getLength(); - else if (location == ReferenceType::Location::CallData) + else if (location == DataLocation::CallData) // length is stored on the stack m_context << eth::Instruction::SWAP1; else @@ -476,20 +476,20 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const m_context << eth::Instruction::SWAP1; if (_arrayType.isDynamicallySized()) { - if (location == ReferenceType::Location::Storage) + if (location == DataLocation::Storage) CompilerUtils(m_context).computeHashStatic(); - else if (location == ReferenceType::Location::Memory) + else if (location == DataLocation::Memory) m_context << u256(32) << eth::Instruction::ADD; } // stack: switch (location) { - case ReferenceType::Location::CallData: + case DataLocation::CallData: if (!_arrayType.isByteArray()) - m_context - << eth::Instruction::SWAP1 - << _arrayType.getBaseType()->getCalldataEncodedSize() - << eth::Instruction::MUL; + { + m_context << eth::Instruction::SWAP1; + m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL; + } m_context << eth::Instruction::ADD; if (_arrayType.getBaseType()->isValueType()) CompilerUtils(m_context).loadFromMemoryDynamic( @@ -499,7 +499,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const false ); break; - case ReferenceType::Location::Storage: + case DataLocation::Storage: m_context << eth::Instruction::SWAP1; if (_arrayType.getBaseType()->getStorageBytes() <= 16) { @@ -527,7 +527,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const m_context << eth::Instruction::ADD << u256(0); } break; - case ReferenceType::Location::Memory: + case DataLocation::Memory: solAssert(false, "Memory lvalues not yet implemented."); } } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 82e98dfff..0b88ed8ae 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -245,21 +245,35 @@ void Compiler::appendCalldataUnpacker( { // We do not check the calldata size, everything is zero-paddedd + //@todo this does not yet support nested arrays + if (_startOffset == u256(-1)) _startOffset = u256(CompilerUtils::dataStartOffset); m_context << _startOffset; for (TypePointer const& type: _typeParameters) { + // stack: v1 v2 ... v(k-1) mem_offset switch (type->getCategory()) { case Type::Category::Array: { auto const& arrayType = dynamic_cast(*type); - if (arrayType.location() == ReferenceType::Location::CallData) + solAssert(arrayType.location() != DataLocation::Storage, ""); + solAssert(!arrayType.getBaseType()->isDynamicallySized(), "Nested arrays not yet implemented."); + if (_fromMemory) + { + solAssert(arrayType.location() == DataLocation::Memory, ""); + // compute data pointer + //@todo once we support nested arrays, this offset needs to be dynamic. + m_context << eth::Instruction::DUP1 << _startOffset << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP1 << u256(0x20) << eth::Instruction::ADD; + } + else { - solAssert(!_fromMemory, ""); - if (type->isDynamicallySized()) + // first load from calldata and potentially convert to memory if arrayType is memory + TypePointer calldataType = arrayType.copyForLocation(DataLocation::CallData, false); + if (calldataType->isDynamicallySized()) { // put on stack: data_pointer length CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory); @@ -276,17 +290,17 @@ void Compiler::appendCalldataUnpacker( { // leave the pointer on the stack m_context << eth::Instruction::DUP1; - m_context << u256(type->getCalldataEncodedSize()) << eth::Instruction::ADD; + m_context << u256(calldataType->getCalldataEncodedSize()) << eth::Instruction::ADD; + } + if (arrayType.location() == DataLocation::Memory) + { + // copy to memory + // move calldata type up again + CompilerUtils(m_context).moveIntoStack(calldataType->getSizeOnStack()); + CompilerUtils(m_context).convertType(*calldataType, arrayType); + // fetch next pointer again + CompilerUtils(m_context).moveToStackTop(arrayType.getSizeOnStack()); } - } - else - { - solAssert(arrayType.location() == ReferenceType::Location::Memory, ""); - // compute data pointer - m_context << eth::Instruction::DUP1 << _startOffset << eth::Instruction::ADD; - if (!_fromMemory) - solAssert(false, "Not yet implemented."); - m_context << eth::Instruction::SWAP1 << u256(0x20) << eth::Instruction::ADD; } break; } diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index d4e705a3c..4d57dc926 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -107,16 +107,18 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound auto const& type = dynamic_cast(_type); solAssert(type.isByteArray(), "Non byte arrays not yet implemented here."); - if (type.location() == ReferenceType::Location::CallData) + if (type.location() == DataLocation::CallData) { + if (!type.isDynamicallySized()) + m_context << type.getLength(); // stack: target source_offset source_len m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5; - // stack: target source_offset source_len source_len source_offset target + // stack: target source_offset source_len source_len source_offset target m_context << eth::Instruction::CALLDATACOPY; m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP; } - else if (type.location() == ReferenceType::Location::Memory) + else if (type.location() == DataLocation::Memory) { // memcpy using the built-in contract ArrayUtils(m_context).retrieveLength(type); @@ -183,7 +185,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound } else { - solAssert(type.location() == ReferenceType::Location::Storage, ""); + solAssert(type.location() == DataLocation::Storage, ""); m_context << eth::Instruction::POP; // remove offset, arrays always start new slot m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; // stack here: memory_offset storage_offset length_bytes @@ -276,7 +278,10 @@ void CompilerUtils::encodeToMemory( copyToStackTop(argSize - stackPos + dynPointers + 2, _givenTypes[i]->getSizeOnStack()); solAssert(!!targetType, "Externalable type expected."); TypePointer type = targetType; - if (_givenTypes[i]->isInStorage()) + if ( + _givenTypes[i]->dataStoredIn(DataLocation::Storage) || + _givenTypes[i]->dataStoredIn(DataLocation::CallData) + ) type = _givenTypes[i]; // delay conversion else convertType(*_givenTypes[i], *targetType, true); @@ -307,13 +312,13 @@ void CompilerUtils::encodeToMemory( // stack: ... // copy length to memory m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack()); - if (arrayType.location() == ReferenceType::Location::CallData) + if (arrayType.location() == DataLocation::CallData) m_context << eth::Instruction::DUP2; // length is on stack - else if (arrayType.location() == ReferenceType::Location::Storage) + else if (arrayType.location() == DataLocation::Storage) m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD; else { - solAssert(arrayType.location() == ReferenceType::Location::Memory, ""); + solAssert(arrayType.location() == DataLocation::Memory, ""); m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD; } // stack: ... @@ -435,18 +440,18 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp ArrayType const& targetType = dynamic_cast(_targetType); switch (targetType.location()) { - case ReferenceType::Location::Storage: + case DataLocation::Storage: // Other cases are done explicitly in LValue::storeValue, and only possible by assignment. solAssert( targetType.isPointer() && - typeOnStack.location() == ReferenceType::Location::Storage, + typeOnStack.location() == DataLocation::Storage, "Invalid conversion to storage type." ); break; - case ReferenceType::Location::Memory: + case DataLocation::Memory: { // Copy the array to a free position in memory, unless it is already in memory. - if (typeOnStack.location() != ReferenceType::Location::Memory) + if (typeOnStack.location() != DataLocation::Memory) { // stack: (variably sized) unsigned stackSize = typeOnStack.getSizeOnStack(); @@ -455,7 +460,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp // stack: (variably sized) if (targetType.isDynamicallySized()) { - bool fromStorage = (typeOnStack.location() == ReferenceType::Location::Storage); + bool fromStorage = (typeOnStack.location() == DataLocation::Storage); // store length if (fromStorage) { @@ -486,11 +491,25 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp // Stack storeFreeMemoryPointer(); } - else if (typeOnStack.location() == ReferenceType::Location::CallData) + else if (typeOnStack.location() == DataLocation::CallData) { - // Stack: - //@todo - solAssert(false, "Not yet implemented."); + // Stack: [] + // length is present if dynamically sized + fetchFreeMemoryPointer(); + moveIntoStack(typeOnStack.getSizeOnStack()); + // stack: memptr calldataoffset [] + if (typeOnStack.isDynamicallySized()) + { + solAssert(targetType.isDynamicallySized(), ""); + m_context << eth::Instruction::DUP3 << eth::Instruction::DUP2; + storeInMemoryDynamic(IntegerType(256)); + moveIntoStack(typeOnStack.getSizeOnStack()); + } + else + m_context << eth::Instruction::DUP2 << eth::Instruction::SWAP1; + // stack: mem_ptr mem_data_ptr calldataoffset [] + storeInMemoryDynamic(typeOnStack); + storeFreeMemoryPointer(); } // nothing to do for memory to memory break; @@ -507,8 +526,8 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp auto& targetType = dynamic_cast(_targetType); auto& stackType = dynamic_cast(_typeOnStack); solAssert( - targetType.location() == ReferenceType::Location::Storage && - stackType.location() == ReferenceType::Location::Storage, + targetType.location() == DataLocation::Storage && + stackType.location() == DataLocation::Storage, "Non-storage structs not yet implemented." ); solAssert( diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index 32dc93a2c..a880f9ee4 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -99,8 +99,9 @@ public: bool _copyDynamicDataInPlace = false ); - /// Appends code for an implicit or explicit type conversion. For now this comprises only erasing - /// higher-order bits (@see appendHighBitCleanup) when widening integer. + /// Appends code for an implicit or explicit type conversion. This includes erasing higher + /// order bits (@see appendHighBitCleanup) when widening integer but also copy to memory + /// if a reference type is converted from calldata or storage to memory. /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be /// necessary. void convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index c98d76f3f..bfb945d8f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -109,34 +109,40 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& } unsigned retSizeOnStack = 0; solAssert(accessorType.getReturnParameterTypes().size() >= 1, ""); + auto const& returnTypes = accessorType.getReturnParameterTypes(); if (StructType const* structType = dynamic_cast(returnType.get())) { // remove offset m_context << eth::Instruction::POP; auto const& names = accessorType.getReturnParameterNames(); - auto const& types = accessorType.getReturnParameterTypes(); // struct for (size_t i = 0; i < names.size(); ++i) { - if (types[i]->getCategory() == Type::Category::Mapping || types[i]->getCategory() == Type::Category::Array) + if (returnTypes[i]->getCategory() == Type::Category::Mapping) continue; + if (auto arrayType = dynamic_cast(returnTypes[i].get())) + if (!arrayType->isByteArray()) + continue; pair const& offsets = structType->getStorageOffsetsOfMember(names[i]); m_context << eth::Instruction::DUP1 << u256(offsets.first) << eth::Instruction::ADD << u256(offsets.second); - StorageItem(m_context, *types[i]).retrieveValue(SourceLocation(), true); - solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 is not yet implemented."); - m_context << eth::Instruction::SWAP1; - retSizeOnStack += types[i]->getSizeOnStack(); + TypePointer memberType = structType->getMemberType(names[i]); + StorageItem(m_context, *memberType).retrieveValue(SourceLocation(), true); + utils().convertType(*memberType, *returnTypes[i]); + utils().moveToStackTop(returnTypes[i]->getSizeOnStack()); + retSizeOnStack += returnTypes[i]->getSizeOnStack(); } // remove slot m_context << eth::Instruction::POP; } else { - // simple value - solAssert(accessorType.getReturnParameterTypes().size() == 1, ""); + // simple value or array + solAssert(returnTypes.size() == 1, ""); StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true); - retSizeOnStack = returnType->getSizeOnStack(); + utils().convertType(*returnType, *returnTypes.front()); + retSizeOnStack = returnTypes.front()->getSizeOnStack(); } + solAssert(retSizeOnStack == utils().getSizeOnStack(returnTypes), ""); solAssert(retSizeOnStack <= 15, "Stack is too deep."); m_context << eth::dupInstruction(retSizeOnStack + 1); m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); @@ -147,7 +153,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) CompilerContext::LocationSetter locationSetter(m_context, _assignment); _assignment.getRightHandSide().accept(*this); TypePointer type = _assignment.getRightHandSide().getType(); - if (!_assignment.getType()->isInStorage()) + if (!_assignment.getType()->dataStoredIn(DataLocation::Storage)) { utils().convertType(*type, *_assignment.getType()); type = _assignment.getType(); @@ -712,10 +718,10 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) else switch (type.location()) { - case ReferenceType::Location::CallData: + case DataLocation::CallData: m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; break; - case ReferenceType::Location::Storage: + case DataLocation::Storage: setLValue(_memberAccess, type); break; default: @@ -758,13 +764,13 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); // remove storage byte offset - if (arrayType.location() == ReferenceType::Location::Storage) + if (arrayType.location() == DataLocation::Storage) m_context << eth::Instruction::POP; _indexAccess.getIndexExpression()->accept(*this); // stack layout: [] ArrayUtils(m_context).accessIndex(arrayType); - if (arrayType.location() == ReferenceType::Location::Storage) + if (arrayType.location() == DataLocation::Storage) { if (arrayType.isByteArray()) { diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index e60797967..87f9da7ee 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -439,7 +439,7 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) "Location has to be calldata for external functions " "(remove the \"memory\" or \"storage\" keyword)." )); - type = ref->copyForLocation(ReferenceType::Location::CallData, true); + type = ref->copyForLocation(DataLocation::CallData, true); } else if (_variable.isCallableParameter() && _variable.getScope()->isPublic()) { @@ -449,7 +449,7 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) "Location has to be memory for publicly visible functions " "(remove the \"storage\" keyword)." )); - type = ref->copyForLocation(ReferenceType::Location::Memory, true); + type = ref->copyForLocation(DataLocation::Memory, true); } else { @@ -458,8 +458,8 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) bool isPointer = !_variable.isStateVariable(); type = ref->copyForLocation( loc == Location::Memory ? - ReferenceType::Location::Memory : - ReferenceType::Location::Storage, + DataLocation::Memory : + DataLocation::Storage, isPointer ); } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index bedd2e7b0..b90b88846 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -144,12 +144,13 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) else if (_typeToken == Token::Bool) return make_shared(); else if (_typeToken == Token::Bytes) - return make_shared(ReferenceType::Location::Storage); + return make_shared(DataLocation::Storage); else if (_typeToken == Token::String) - return make_shared(ReferenceType::Location::Storage, true); + return make_shared(DataLocation::Storage, true); else - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + - std::string(Token::toString(_typeToken)) + " to type.")); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment( + "Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type." + )); } TypePointer Type::fromElementaryTypeName(string const& _name) @@ -180,7 +181,7 @@ TypePointer Type::fromMapping(ElementaryTypeName& _keyType, TypeName& _valueType if (!valueType) BOOST_THROW_EXCEPTION(_valueType.createTypeError("Invalid type name.")); // Convert value type to storage reference. - valueType = ReferenceType::copyForLocationIfReference(ReferenceType::Location::Storage, valueType); + valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType); return make_shared(keyType, valueType); } @@ -198,10 +199,10 @@ TypePointer Type::fromArrayTypeName(TypeName& _baseTypeName, Expression* _length auto const* length = dynamic_cast(_length->getType().get()); if (!length) BOOST_THROW_EXCEPTION(_length->createTypeError("Invalid array length.")); - return make_shared(ReferenceType::Location::Storage, baseType, length->literalValue(nullptr)); + return make_shared(DataLocation::Storage, baseType, length->literalValue(nullptr)); } else - return make_shared(ReferenceType::Location::Storage, baseType); + return make_shared(DataLocation::Storage, baseType); } TypePointer Type::forLiteral(Literal const& _literal) @@ -670,7 +671,7 @@ TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const return _operator == Token::Delete ? make_shared() : TypePointer(); } -TypePointer ReferenceType::copyForLocationIfReference(Location _location, TypePointer const& _type) +TypePointer ReferenceType::copyForLocationIfReference(DataLocation _location, TypePointer const& _type) { if (auto type = dynamic_cast(_type.get())) return type->copyForLocation(_location, false); @@ -686,11 +687,11 @@ string ReferenceType::stringForReferencePart() const { switch (m_location) { - case Location::Storage: + case DataLocation::Storage: return string("storage ") + (m_isPointer ? "pointer" : "ref"); - case Location::CallData: + case DataLocation::CallData: return "calldata"; - case Location::Memory: + case DataLocation::Memory: return "memory"; } solAssert(false, ""); @@ -705,11 +706,11 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString()) return false; // memory/calldata to storage can be converted, but only to a direct storage reference - if (convertTo.location() == Location::Storage && location() != Location::Storage && convertTo.isPointer()) + if (convertTo.location() == DataLocation::Storage && location() != DataLocation::Storage && convertTo.isPointer()) return false; - if (convertTo.location() == Location::CallData && location() != convertTo.location()) + if (convertTo.location() == DataLocation::CallData && location() != convertTo.location()) return false; - if (convertTo.location() == Location::Storage && !convertTo.isPointer()) + if (convertTo.location() == DataLocation::Storage && !convertTo.isPointer()) { // Less restrictive conversion, since we need to copy anyway. if (!getBaseType()->isImplicitlyConvertibleTo(*convertTo.getBaseType())) @@ -788,10 +789,10 @@ u256 ArrayType::getStorageSize() const unsigned ArrayType::getSizeOnStack() const { - if (m_location == Location::CallData) + if (m_location == DataLocation::CallData) // offset [length] (stack top) return 1 + (isDynamicallySized() ? 1 : 0); - else if (m_location == Location::Storage) + else if (m_location == DataLocation::Storage) // storage_key storage_offset return 2; else @@ -828,12 +829,12 @@ TypePointer ArrayType::externalType() const return TypePointer(); if (isDynamicallySized()) - return std::make_shared(Location::CallData, m_baseType->externalType()); + return std::make_shared(DataLocation::CallData, m_baseType->externalType()); else - return std::make_shared(Location::CallData, m_baseType->externalType(), m_length); + return std::make_shared(DataLocation::CallData, m_baseType->externalType(), m_length); } -TypePointer ArrayType::copyForLocation(ReferenceType::Location _location, bool _isPointer) const +TypePointer ArrayType::copyForLocation(DataLocation _location, bool _isPointer) const { auto copy = make_shared(_location); copy->m_isPointer = _isPointer; @@ -949,9 +950,9 @@ bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const return false; auto& convertTo = dynamic_cast(_convertTo); // memory/calldata to storage can be converted, but only to a direct storage reference - if (convertTo.location() == Location::Storage && location() != Location::Storage && convertTo.isPointer()) + if (convertTo.location() == DataLocation::Storage && location() != DataLocation::Storage && convertTo.isPointer()) return false; - if (convertTo.location() == Location::CallData && location() != convertTo.location()) + if (convertTo.location() == DataLocation::CallData && location() != convertTo.location()) return false; return this->m_struct == convertTo.m_struct; } @@ -1009,7 +1010,7 @@ MemberList const& StructType::getMembers() const return *m_members; } -TypePointer StructType::copyForLocation(ReferenceType::Location _location, bool _isPointer) const +TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const { auto copy = make_shared(m_struct); copy->m_location = _location; @@ -1115,6 +1116,9 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): } else if (auto arrayType = dynamic_cast(returnType.get())) { + if (arrayType->isByteArray()) + // Return byte arrays as as whole. + break; returnType = arrayType->getBaseType(); paramNames.push_back(""); paramTypes.push_back(make_shared(256)); @@ -1128,15 +1132,21 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): if (auto structType = dynamic_cast(returnType.get())) { for (auto const& member: structType->getMembers()) - if (member.type->getCategory() != Category::Mapping && member.type->getCategory() != Category::Array) + if (member.type->getCategory() != Category::Mapping) { - retParamNames.push_back(member.name); + if (auto arrayType = dynamic_cast(member.type.get())) + if (!arrayType->isByteArray()) + continue; retParams.push_back(member.type); + retParamNames.push_back(member.name); } } else { - retParams.push_back(returnType); + retParams.push_back(ReferenceType::copyForLocationIfReference( + DataLocation::Memory, + returnType + )); retParamNames.push_back(""); } @@ -1549,7 +1559,7 @@ MagicType::MagicType(MagicType::Kind _kind): {"sender", make_shared(0, IntegerType::Modifier::Address)}, {"gas", make_shared(256)}, {"value", make_shared(256)}, - {"data", make_shared(ReferenceType::Location::CallData)}, + {"data", make_shared(DataLocation::CallData)}, {"sig", make_shared(4)} }); break; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 70f7807c8..cca5dde71 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -44,6 +44,8 @@ using FunctionTypePointer = std::shared_ptr; using TypePointers = std::vector; +enum class DataLocation { Storage, CallData, Memory }; + /** * Helper class to compute storage offsets of members of structs and contracts. */ @@ -202,8 +204,9 @@ public: /// This returns the corresponding integer type for IntegerConstantTypes and the pointer type /// for storage reference types. virtual TypePointer mobileType() const { return shared_from_this(); } - /// @returns true if this type is a storage pointer or reference. - virtual bool isInStorage() const { return false; } + /// @returns true if this is a non-value type and the data of this type is stored at the + /// given location. + virtual bool dataStoredIn(DataLocation) const { return false; } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } @@ -367,16 +370,15 @@ public: class ReferenceType: public Type { public: - enum class Location { Storage, CallData, Memory }; - explicit ReferenceType(Location _location): m_location(_location) {} - Location location() const { return m_location; } + explicit ReferenceType(DataLocation _location): m_location(_location) {} + DataLocation location() const { return m_location; } /// @returns a copy of this type with location (recursively) changed to @a _location, /// whereas isPointer is only shallowly changed - the deep copy is always a bound reference. - virtual TypePointer copyForLocation(Location _location, bool _isPointer) const = 0; + virtual TypePointer copyForLocation(DataLocation _location, bool _isPointer) const = 0; virtual TypePointer mobileType() const override { return copyForLocation(m_location, true); } - virtual bool isInStorage() const override { return m_location == Location::Storage; } + virtual bool dataStoredIn(DataLocation _location) const override { return m_location == _location; } /// Storage references can be pointers or bound references. In general, local variables are of /// pointer type, state variables are bound references. Assignments to pointers or deleting @@ -392,14 +394,14 @@ public: /// @returns a copy of @a _type having the same location as this (and is not a pointer type) /// if _type is a reference type and an unmodified copy of _type otherwise. /// This function is mostly useful to modify inner types appropriately. - static TypePointer copyForLocationIfReference(Location _location, TypePointer const& _type); + static TypePointer copyForLocationIfReference(DataLocation _location, TypePointer const& _type); protected: TypePointer copyForLocationIfReference(TypePointer const& _type) const; /// @returns a human-readable description of the reference part of the type. std::string stringForReferencePart() const; - Location m_location = Location::Storage; + DataLocation m_location = DataLocation::Storage; bool m_isPointer = true; }; @@ -416,20 +418,20 @@ public: virtual Category getCategory() const override { return Category::Array; } /// Constructor for a byte array ("bytes") and string. - explicit ArrayType(Location _location, bool _isString = false): + explicit ArrayType(DataLocation _location, bool _isString = false): ReferenceType(_location), m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes), m_baseType(std::make_shared(1)) { } /// Constructor for a dynamically sized array type ("type[]") - ArrayType(Location _location, TypePointer const& _baseType): + ArrayType(DataLocation _location, TypePointer const& _baseType): ReferenceType(_location), m_baseType(copyForLocationIfReference(_baseType)) { } /// Constructor for a fixed-size array type ("type[20]") - ArrayType(Location _location, TypePointer const& _baseType, u256 const& _length): + ArrayType(DataLocation _location, TypePointer const& _baseType, u256 const& _length): ReferenceType(_location), m_baseType(copyForLocationIfReference(_baseType)), m_hasDynamicLength(false), @@ -457,7 +459,7 @@ public: TypePointer const& getBaseType() const { solAssert(!!m_baseType, ""); return m_baseType;} u256 const& getLength() const { return m_length; } - TypePointer copyForLocation(Location _location, bool _isPointer) const override; + TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override; private: /// String is interpreted as a subtype of Bytes. @@ -536,7 +538,7 @@ public: virtual Category getCategory() const override { return Category::Struct; } explicit StructType(StructDefinition const& _struct): //@todo only storage until we have non-storage structs - ReferenceType(Location::Storage), m_struct(_struct) {} + ReferenceType(DataLocation::Storage), m_struct(_struct) {} virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; @@ -547,7 +549,7 @@ public: virtual MemberList const& getMembers() const override; - TypePointer copyForLocation(Location _location, bool _isPointer) const override; + TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override; std::pair const& getStorageOffsetsOfMember(std::string const& _name) const; @@ -639,8 +641,11 @@ public: FunctionTypePointer externalFunctionType() const; virtual TypePointer externalType() const override { return externalFunctionType(); } + /// Creates the type of a function. explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); + /// Creates the accessor function type of a state variable. explicit FunctionType(VariableDeclaration const& _varDecl); + /// Creates the function type of an event. explicit FunctionType(EventDefinition const& _event); FunctionType( strings const& _parameterTypes, diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 109481edc..106242813 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4257,6 +4257,84 @@ BOOST_AUTO_TEST_CASE(return_string) BOOST_CHECK(callContractFunction("s()") == args); } +BOOST_AUTO_TEST_CASE(return_multiple_strings_of_various_sizes) +{ + char const* sourceCode = R"( + contract Main { + string public s1; + string public s2; + function set(string _s1, uint x, string _s2) external returns (uint) { + s1 = _s1; + s2 = _s2; + return x; + } + function get() returns (string r1, string r2) { + r1 = s1; + r2 = s2; + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + string s1( + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + ); + string s2( + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + ); + vector lengthes{0, 30, 32, 63, 64, 65, 210, 300}; + for (auto l1: lengthes) + for (auto l2: lengthes) + { + bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); + bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2)); + bytes args = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2; + BOOST_REQUIRE( + callContractFunction("set(string,uint256,string)", asString(args)) == + encodeArgs(u256(l1)) + ); + bytes result = encodeArgs(u256(0x40), u256(0x40 + dyn1.size())) + dyn1 + dyn2; + BOOST_CHECK(callContractFunction("get()") == result); + BOOST_CHECK(callContractFunction("s1()") == encodeArgs(0x20) + dyn1); + BOOST_CHECK(callContractFunction("s2()") == encodeArgs(0x20) + dyn2); + } +} + +BOOST_AUTO_TEST_CASE(accessor_involving_strings) +{ + char const* sourceCode = R"( + contract Main { + struct stringData { string a; uint b; string c; } + mapping(uint => stringData[]) public data; + function set(uint x, uint y, string a, uint b, string c) external returns (bool) { + data[x].length = y + 1; + data[x][y].a = a; + data[x][y].b = b; + data[x][y].c = c; + return true; + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"); + bytes s1Data = encodeArgs(u256(s1.length()), s1); + bytes s2Data = encodeArgs(u256(s2.length()), s2); + u256 b = 765; + u256 x = 7; + u256 y = 123; + bytes args = encodeArgs(x, y, u256(0xa0), b, u256(0xa0 + s1Data.size()), s1Data, s2Data); + bytes result = encodeArgs(u256(0x60), b, u256(0x60 + s1Data.size()), s1Data, s2Data); + BOOST_REQUIRE(callContractFunction("set(uint256,uint256,string,uint256,string)", asString(args)) == encodeArgs(true)); + BOOST_REQUIRE(callContractFunction("data(uint256,uint256)", x, y) == result); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp index 718798a5a..7892de673 100644 --- a/test/libsolidity/SolidityTypes.cpp +++ b/test/libsolidity/SolidityTypes.cpp @@ -77,13 +77,13 @@ BOOST_AUTO_TEST_CASE(storage_layout_mapping) BOOST_AUTO_TEST_CASE(storage_layout_arrays) { - BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(1), 32).getStorageSize() == 1); - BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(1), 33).getStorageSize() == 2); - BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(2), 31).getStorageSize() == 2); - BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(7), 8).getStorageSize() == 2); - BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(7), 9).getStorageSize() == 3); - BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(31), 9).getStorageSize() == 9); - BOOST_CHECK(ArrayType(ReferenceType::Location::Storage, make_shared(32), 9).getStorageSize() == 9); + BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared(1), 32).getStorageSize() == 1); + BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared(1), 33).getStorageSize() == 2); + BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared(2), 31).getStorageSize() == 2); + BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared(7), 8).getStorageSize() == 2); + BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared(7), 9).getStorageSize() == 3); + BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared(31), 9).getStorageSize() == 9); + BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared(32), 9).getStorageSize() == 9); } BOOST_AUTO_TEST_SUITE_END() From 3264250b5de65b0db8a041826bbd8e38a11bb1a9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Jun 2015 14:35:55 +0200 Subject: [PATCH 051/103] Removed spaces between code and comment. --- libethcore/KeyManager.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libethcore/KeyManager.h b/libethcore/KeyManager.h index d9bb6457c..a2b5a4e07 100644 --- a/libethcore/KeyManager.h +++ b/libethcore/KeyManager.h @@ -38,8 +38,10 @@ struct KeyInfo KeyInfo() = default; KeyInfo(h256 const& _passHash, std::string const& _accountName): passHash(_passHash), accountName(_accountName) {} - h256 passHash; ///< Hash of the password or h256() / UnknownPassword if unknown. - std::string accountName; ///< Name of the key, or JSON key info if begins with '{'. + /// Hash of the password or h256() / UnknownPassword if unknown. + h256 passHash; + /// Name of the key, or JSON key info if begins with '{'. + std::string accountName; }; static h256 const UnknownPassword; From 06770736bd662c26bb04abe0d5a0b5e14d0a44d4 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 17 Jun 2015 15:32:27 +0200 Subject: [PATCH 052/103] style 2 --- test/libethereum/blockchain.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index de28d30ff..4dc1993a9 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -582,8 +582,11 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector updatePoW(uncleBlockFromFields); - uncleBlockFromFields.nonce = overwrite == "nonce" ? Nonce(uncleHeaderObj["nonce"].get_str()) : uncleBlockFromFields.nonce; - uncleBlockFromFields.mixHash = overwrite == "mixHash" ? h256(uncleHeaderObj["mixHash"].get_str()) : uncleBlockFromFields.mixHash; + if (overwrite == "nonce") + uncleBlockFromFields.nonce = Nonce(uncleHeaderObj["nonce"].get_str()); + + if (overwrite == "mixHash") + uncleBlockFromFields.mixHash = h256(uncleHeaderObj["mixHash"].get_str()); writeBlockHeaderToJson(uncleHeaderObj, uncleBlockFromFields); From 3660c4433695436b26118d78aee750952e1bf2fb Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 3 Jun 2015 17:21:29 +0300 Subject: [PATCH 053/103] FuzzTests: Boost Macro --- test/TestHelper.h | 16 +++ test/fuzzTesting/CMakeLists.txt | 5 + test/fuzzTesting/createRandomTest.cpp | 143 ++++++++++++++++++++++++++ test/libethereum/transaction.cpp | 43 ++++---- 4 files changed, 186 insertions(+), 21 deletions(-) create mode 100644 test/fuzzTesting/createRandomTest.cpp diff --git a/test/TestHelper.h b/test/TestHelper.h index 8f0c73bf3..eaeed619a 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -31,6 +31,19 @@ #include #include +#define DONTUSE_BOOST_MACROS +#ifdef DONTUSE_BOOST_MACROS + #define TBOOST_THROW_EXCEPTION(arg) throw; + #define TBOOST_REQUIRE(arg) if(arg == false) throw; + #define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw; + #define TBOOST_WARN_MESSAGE(arg1, arg2) throw; +#else + #define TBOOST_THROW_EXCEPTION(arg) BOOST_THROW_EXCEPTION(arg) + #define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg) + #define TBOOST_CHECK_MESSAGE(arg1, arg2) BOOST_CHECK_MESSAGE(arg1, arg2) + #define TBOOST_WARN_MESSAGE(arg1, arg2) BOOST_WARN_MESSAGE(arg1, arg2) +#endif + namespace dev { namespace eth @@ -163,6 +176,9 @@ eth::LastHashes lastHashes(u256 _currentBlockNumber); json_spirit::mObject fillJsonWithState(eth::State _state); json_spirit::mObject fillJsonWithTransaction(eth::Transaction _txn); +//Fill Test Functions +void doTransactionTests(json_spirit::mValue& _v, bool _fillin); + template void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) { diff --git a/test/fuzzTesting/CMakeLists.txt b/test/fuzzTesting/CMakeLists.txt index 371d6504d..4024b7956 100644 --- a/test/fuzzTesting/CMakeLists.txt +++ b/test/fuzzTesting/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp") add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp") add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp" ) @@ -32,3 +33,7 @@ target_link_libraries(checkRandomStateTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES target_link_libraries(checkRandomStateTest ethereum) target_link_libraries(checkRandomStateTest ethcore) target_link_libraries(checkRandomStateTest testutils) +target_link_libraries(createRandomTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) +target_link_libraries(createRandomTest ethereum) +target_link_libraries(createRandomTest ethcore) +target_link_libraries(createRandomTest testutils) diff --git a/test/fuzzTesting/createRandomTest.cpp b/test/fuzzTesting/createRandomTest.cpp new file mode 100644 index 000000000..92fd21b76 --- /dev/null +++ b/test/fuzzTesting/createRandomTest.cpp @@ -0,0 +1,143 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file createRandomTest.cpp + * @author Dimitry Khokhlov + * @date 2015 + */ + +#include +#include + +#include +#include + + +extern std::string const c_testExampleTransactionTest; +std::vector getTypes(); +void parseTestWithTypes(std::string& test); +void randomTransactionTest(); +void randomBlockChainTest(); + +int main(int argc, char *argv[]) +{ + std::string testSuite; + for (auto i = 0; i < argc; ++i) + { + auto arg = std::string{argv[i]}; + dev::test::Options& options = const_cast(dev::test::Options::get()); + if (arg == "--fulloutput") + options.fulloutput = true; + if (arg == "-t" && i + 1 < argc) + { + testSuite = argv[i + 1]; + if (testSuite != "BlockChainTests" && testSuite != "TransactionTests") + testSuite = ""; + } + } + + if (testSuite == "") + std::cout << "Error! Test suite not supported! (Usage -t TestSuite)"; + else + if (testSuite == "BlockChainTests") + randomBlockChainTest(); + else + if (testSuite == "TransactionTests") + randomTransactionTest(); + + return 0; +} + +void randomTransactionTest() +{ + std::string newTest = c_testExampleTransactionTest; + parseTestWithTypes(newTest); + json_spirit::mValue v; + json_spirit::read_string(newTest, v); + dev::test::doTransactionTests(v, true); + std::cout << json_spirit::write_string(v, true); +} + +void randomBlockChainTest() +{ + +} + +/// Parse Test string replacing keywords to fuzzed values +void parseTestWithTypes(std::string& test) +{ + std::vector types = getTypes(); + for (unsigned i = 0; i < types.size(); i++) + { + std::size_t pos = test.find(types.at(i)); + while (pos != std::string::npos) + { + if (types.at(i) == "[CODE]") + test.replace(pos, 6, "0x"+dev::test::RandomCode::generate(10)); + else + if (types.at(i) == "[HEX]") + test.replace(pos, 5, dev::test::RandomCode::randomUniIntHex()); + else + if (types.at(i) == "[HASH20]") + test.replace(pos, 8, dev::test::RandomCode::rndByteSequence(20)); + else + if (types.at(i) == "[0xHASH32]") + test.replace(pos, 10, "0x" + dev::test::RandomCode::rndByteSequence(32)); + else + if (types.at(i) == "[V]") + { + int random = dev::test::RandomCode::randomUniInt() % 100; + if (random < 30) + test.replace(pos, 3, "28"); + else + if (random < 60) + test.replace(pos, 3, "29"); + else + test.replace(pos, 3, "0x" + dev::test::RandomCode::rndByteSequence(1)); + } + + pos = test.find(types.at(i)); + } + } +} + +std::vector getTypes() +{ + return {"[CODE]", "[HEX]", "[HASH20]", "[0xHASH32]", "[V]"}; +} + + +std::string const c_testExampleTransactionTest = R"( +{ +"TransactionTest" : { + "transaction" : + { + "data" : "[CODE]", + "gasLimit" : "[HEX]", + "gasPrice" : "[HEX]", + "nonce" : "[HEX]", + "to" : "[HASH20]", + "value" : "[HEX]", + "v" : "[V]", + "r" : "[0xHASH32]", + "s" : "[0xHASH32]" + } + } +} +)"; + + + diff --git a/test/libethereum/transaction.cpp b/test/libethereum/transaction.cpp index 017e51ded..ad20331b3 100644 --- a/test/libethereum/transaction.cpp +++ b/test/libethereum/transaction.cpp @@ -21,6 +21,7 @@ */ #include "../TestHelper.h" +#include "test/fuzzTesting/fuzzHelper.h" using namespace std; using namespace json_spirit; @@ -38,7 +39,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) if (_fillin) { - BOOST_REQUIRE(o.count("transaction") > 0); + TBOOST_REQUIRE((o.count("transaction") > 0)); mObject tObj = o["transaction"].get_obj(); //Construct Rlp of the given transaction @@ -49,7 +50,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); if (!txFromFields.signature().isValid()) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); + TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); o["sender"] = toString(txFromFields.sender()); o["transaction"] = ImportTest::makeAllFieldsHex(tObj); @@ -63,9 +64,9 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { bool expectInValid = (o["expect"].get_str() == "invalid"); if (Options::get().checkState) - BOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!"); + {TBOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");} else - BOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!"); + {TBOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");} o.erase(o.find("expect")); } @@ -76,16 +77,16 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { bool expectValid = (o["expect"].get_str() == "valid"); if (Options::get().checkState) - BOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!"); + {TBOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");} else - BOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!"); + {TBOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");} o.erase(o.find("expect")); } } else { - BOOST_REQUIRE(o.count("rlp") > 0); + TBOOST_REQUIRE((o.count("rlp") > 0)); Transaction txFromRlp; try { @@ -93,39 +94,39 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) RLP rlp(stream); txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything); if (!txFromRlp.signature().isValid()) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); + TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); } catch(Exception const& _e) { cnote << i.first; cnote << "Transaction Exception: " << diagnostic_information(_e); - BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); + TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!"); continue; } catch(...) { - BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); + TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!"); continue; } - BOOST_REQUIRE(o.count("transaction") > 0); + TBOOST_REQUIRE((o.count("transaction") > 0)); mObject tObj = o["transaction"].get_obj(); Transaction txFromFields(createRLPStreamFromTransactionFields(tObj).out(), CheckTransaction::Everything); //Check the fields restored from RLP to original fields - BOOST_CHECK_MESSAGE(txFromFields.data() == txFromRlp.data(), "Data in given RLP not matching the Transaction data!"); - BOOST_CHECK_MESSAGE(txFromFields.value() == txFromRlp.value(), "Value in given RLP not matching the Transaction value!"); - BOOST_CHECK_MESSAGE(txFromFields.gasPrice() == txFromRlp.gasPrice(), "GasPrice in given RLP not matching the Transaction gasPrice!"); - BOOST_CHECK_MESSAGE(txFromFields.gas() == txFromRlp.gas(),"Gas in given RLP not matching the Transaction gas!"); - BOOST_CHECK_MESSAGE(txFromFields.nonce() == txFromRlp.nonce(),"Nonce in given RLP not matching the Transaction nonce!"); - BOOST_CHECK_MESSAGE(txFromFields.receiveAddress() == txFromRlp.receiveAddress(), "Receive address in given RLP not matching the Transaction 'to' address!"); - BOOST_CHECK_MESSAGE(txFromFields.sender() == txFromRlp.sender(), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!"); - BOOST_CHECK_MESSAGE(txFromFields == txFromRlp, "However, txFromFields != txFromRlp!"); - BOOST_REQUIRE (o.count("sender") > 0); + TBOOST_CHECK_MESSAGE((txFromFields.data() == txFromRlp.data()), "Data in given RLP not matching the Transaction data!"); + TBOOST_CHECK_MESSAGE((txFromFields.value() == txFromRlp.value()), "Value in given RLP not matching the Transaction value!"); + TBOOST_CHECK_MESSAGE((txFromFields.gasPrice() == txFromRlp.gasPrice()), "GasPrice in given RLP not matching the Transaction gasPrice!"); + TBOOST_CHECK_MESSAGE((txFromFields.gas() == txFromRlp.gas()),"Gas in given RLP not matching the Transaction gas!"); + TBOOST_CHECK_MESSAGE((txFromFields.nonce() == txFromRlp.nonce()),"Nonce in given RLP not matching the Transaction nonce!"); + TBOOST_CHECK_MESSAGE((txFromFields.receiveAddress() == txFromRlp.receiveAddress()), "Receive address in given RLP not matching the Transaction 'to' address!"); + TBOOST_CHECK_MESSAGE((txFromFields.sender() == txFromRlp.sender()), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!"); + TBOOST_CHECK_MESSAGE((txFromFields == txFromRlp), "However, txFromFields != txFromRlp!"); + TBOOST_REQUIRE ((o.count("sender") > 0)); Address addressReaded = Address(o["sender"].get_str()); - BOOST_CHECK_MESSAGE(txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!"); + TBOOST_CHECK_MESSAGE((txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded), "Signature address of sender does not match given sender address!"); } }//for }//doTransactionTests From ec0e65d339f9f7d219a6b29b5c6a72c2ab6d922a Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 3 Jun 2015 19:36:41 +0300 Subject: [PATCH 054/103] Random code: Exceptions and outut --- test/TestHelper.h | 8 ++++---- test/fuzzTesting/createRandomTest.cpp | 25 +++++++++++++++++++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/test/TestHelper.h b/test/TestHelper.h index eaeed619a..649d4adf1 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -33,10 +33,10 @@ #define DONTUSE_BOOST_MACROS #ifdef DONTUSE_BOOST_MACROS - #define TBOOST_THROW_EXCEPTION(arg) throw; - #define TBOOST_REQUIRE(arg) if(arg == false) throw; - #define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw; - #define TBOOST_WARN_MESSAGE(arg1, arg2) throw; + #define TBOOST_THROW_EXCEPTION(arg) throw dev::Exception(); + #define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception(); + #define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw dev::Exception(); + #define TBOOST_WARN_MESSAGE(arg1, arg2) throw dev::Exception(); #else #define TBOOST_THROW_EXCEPTION(arg) BOOST_THROW_EXCEPTION(arg) #define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg) diff --git a/test/fuzzTesting/createRandomTest.cpp b/test/fuzzTesting/createRandomTest.cpp index 92fd21b76..2177902d6 100644 --- a/test/fuzzTesting/createRandomTest.cpp +++ b/test/fuzzTesting/createRandomTest.cpp @@ -63,11 +63,28 @@ int main(int argc, char *argv[]) void randomTransactionTest() { - std::string newTest = c_testExampleTransactionTest; - parseTestWithTypes(newTest); + //redirect all output to the stream + std::ostringstream strCout; + std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); + std::cout.rdbuf( strCout.rdbuf() ); + std::cerr.rdbuf( strCout.rdbuf() ); + json_spirit::mValue v; - json_spirit::read_string(newTest, v); - dev::test::doTransactionTests(v, true); + try + { + std::string newTest = c_testExampleTransactionTest; + parseTestWithTypes(newTest); + json_spirit::read_string(newTest, v); + dev::test::doTransactionTests(v, true); + } + catch(...) + { + std::cerr << "Test fill exception!"; + } + + //restroe output + std::cout.rdbuf(oldCoutStreamBuf); + std::cerr.rdbuf(oldCoutStreamBuf); std::cout << json_spirit::write_string(v, true); } From b72edc27d039445b5ea2603b6ff8d94d4aa4d495 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Fri, 5 Jun 2015 15:35:21 +0300 Subject: [PATCH 055/103] createRandomTest: State test --- test/TestHelper.cpp | 14 +-- test/TestHelper.h | 1 + test/fuzzTesting/CMakeLists.txt | 2 +- test/fuzzTesting/createRandomTest.cpp | 119 ++++++++++++++++++++------ test/fuzzTesting/fuzzHelper.cpp | 7 +- test/fuzzTesting/fuzzHelper.h | 6 +- test/libethereum/state.cpp | 14 +-- 7 files changed, 118 insertions(+), 45 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bca0528ff..0e43d278b 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -178,7 +178,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio { stateOptions.m_bHasBalance = true; if (bigint(o["balance"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); + TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); balance = toInt(o["balance"]); } @@ -186,7 +186,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio { stateOptions.m_bHasNonce = true; if (bigint(o["nonce"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); + TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); nonce = toInt(o["nonce"]); } @@ -230,7 +230,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) { //check that every parameter was declared in state object if (!stateOptionMap.second.isAllSet()) - BOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); + TBOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); } } @@ -246,13 +246,13 @@ void ImportTest::importTransaction(json_spirit::mObject& _o) assert(_o.count("data") > 0); if (bigint(_o["nonce"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") ); + TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") ); if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") ); + TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") ); if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") ); + TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") ); if (bigint(_o["value"].get_str()) >= c_max256plus1) - BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") ); + TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") ); m_transaction = _o["to"].get_str().empty() ? Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) : diff --git a/test/TestHelper.h b/test/TestHelper.h index 649d4adf1..df74c2dc3 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -178,6 +178,7 @@ json_spirit::mObject fillJsonWithTransaction(eth::Transaction _txn); //Fill Test Functions void doTransactionTests(json_spirit::mValue& _v, bool _fillin); +void doStateTests(json_spirit::mValue& v, bool _fillin); template void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) diff --git a/test/fuzzTesting/CMakeLists.txt b/test/fuzzTesting/CMakeLists.txt index 4024b7956..f25a2b31e 100644 --- a/test/fuzzTesting/CMakeLists.txt +++ b/test/fuzzTesting/CMakeLists.txt @@ -8,7 +8,7 @@ include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp") +add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp") add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp") add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp" ) diff --git a/test/fuzzTesting/createRandomTest.cpp b/test/fuzzTesting/createRandomTest.cpp index 2177902d6..373207f44 100644 --- a/test/fuzzTesting/createRandomTest.cpp +++ b/test/fuzzTesting/createRandomTest.cpp @@ -25,12 +25,16 @@ #include #include - +//String Variables +extern std::string const c_testExampleStateTest; extern std::string const c_testExampleTransactionTest; + +//Main Test functinos +void fillRandomTest(std::function doTests, std::string const& testString); + +//Helper Functions std::vector getTypes(); void parseTestWithTypes(std::string& test); -void randomTransactionTest(); -void randomBlockChainTest(); int main(int argc, char *argv[]) { @@ -44,7 +48,7 @@ int main(int argc, char *argv[]) if (arg == "-t" && i + 1 < argc) { testSuite = argv[i + 1]; - if (testSuite != "BlockChainTests" && testSuite != "TransactionTests") + if (testSuite != "BlockChainTests" && testSuite != "TransactionTests" && testSuite != "StateTests") testSuite = ""; } } @@ -53,15 +57,18 @@ int main(int argc, char *argv[]) std::cout << "Error! Test suite not supported! (Usage -t TestSuite)"; else if (testSuite == "BlockChainTests") - randomBlockChainTest(); + fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); else if (testSuite == "TransactionTests") - randomTransactionTest(); + fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); + else + if (testSuite == "StateTests") + fillRandomTest(dev::test::doStateTests, c_testExampleStateTest); return 0; } -void randomTransactionTest() +void fillRandomTest(std::function doTests, std::string const& testString) { //redirect all output to the stream std::ostringstream strCout; @@ -72,10 +79,10 @@ void randomTransactionTest() json_spirit::mValue v; try { - std::string newTest = c_testExampleTransactionTest; + std::string newTest = testString; parseTestWithTypes(newTest); json_spirit::read_string(newTest, v); - dev::test::doTransactionTests(v, true); + doTests(v, true); } catch(...) { @@ -88,55 +95,67 @@ void randomTransactionTest() std::cout << json_spirit::write_string(v, true); } -void randomBlockChainTest() -{ - -} - /// Parse Test string replacing keywords to fuzzed values -void parseTestWithTypes(std::string& test) +void parseTestWithTypes(std::string& _test) { + dev::test::RandomCodeOptions options; + options.setWeight(dev::eth::Instruction::STOP, 10); //default 50 + options.setWeight(dev::eth::Instruction::SSTORE, 70); + options.setWeight(dev::eth::Instruction::CALL, 75); + options.addAddress(dev::Address("0xffffffffffffffffffffffffffffffffffffffff")); + options.addAddress(dev::Address("0x1000000000000000000000000000000000000000")); + options.addAddress(dev::Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")); + options.addAddress(dev::Address("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); + options.addAddress(dev::Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")); + options.addAddress(dev::Address("0x0000000000000000000000000000000000000001")); + options.addAddress(dev::Address("0x0000000000000000000000000000000000000002")); + options.addAddress(dev::Address("0x0000000000000000000000000000000000000003")); + options.addAddress(dev::Address("0x0000000000000000000000000000000000000004")); + options.smartCodeProbability = 35; + std::vector types = getTypes(); for (unsigned i = 0; i < types.size(); i++) { - std::size_t pos = test.find(types.at(i)); + std::size_t pos = _test.find(types.at(i)); while (pos != std::string::npos) { if (types.at(i) == "[CODE]") - test.replace(pos, 6, "0x"+dev::test::RandomCode::generate(10)); + _test.replace(pos, 6, "0x"+dev::test::RandomCode::generate(10, options)); else if (types.at(i) == "[HEX]") - test.replace(pos, 5, dev::test::RandomCode::randomUniIntHex()); + _test.replace(pos, 5, dev::test::RandomCode::randomUniIntHex()); else if (types.at(i) == "[HASH20]") - test.replace(pos, 8, dev::test::RandomCode::rndByteSequence(20)); + _test.replace(pos, 8, dev::test::RandomCode::rndByteSequence(20)); else if (types.at(i) == "[0xHASH32]") - test.replace(pos, 10, "0x" + dev::test::RandomCode::rndByteSequence(32)); + _test.replace(pos, 10, "0x" + dev::test::RandomCode::rndByteSequence(32)); + else + if (types.at(i) == "[HASH32]") + _test.replace(pos, 8, dev::test::RandomCode::rndByteSequence(32)); else if (types.at(i) == "[V]") { int random = dev::test::RandomCode::randomUniInt() % 100; if (random < 30) - test.replace(pos, 3, "28"); + _test.replace(pos, 3, "28"); else if (random < 60) - test.replace(pos, 3, "29"); + _test.replace(pos, 3, "29"); else - test.replace(pos, 3, "0x" + dev::test::RandomCode::rndByteSequence(1)); + _test.replace(pos, 3, "0x" + dev::test::RandomCode::rndByteSequence(1)); } - pos = test.find(types.at(i)); + pos = _test.find(types.at(i)); } } } std::vector getTypes() { - return {"[CODE]", "[HEX]", "[HASH20]", "[0xHASH32]", "[V]"}; + return {"[CODE]", "[HEX]", "[HASH20]", "[HASH32]", "[0xHASH32]", "[V]"}; } - std::string const c_testExampleTransactionTest = R"( { "TransactionTest" : { @@ -156,5 +175,49 @@ std::string const c_testExampleTransactionTest = R"( } )"; - - +std::string const c_testExampleStateTest = R"( +{ + "randomStatetest" : { + "env" : { + "currentCoinbase" : "[HASH20]", + "currentDifficulty" : "[HEX]", + "currentGasLimit" : "[HEX]", + "currentNumber" : "[HEX]", + "currentTimestamp" : "[HEX]", + "previousHash" : "[HASH32]" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "[HEX]", + "code" : "[CODE]", + "nonce" : "[V]", + "storage" : { + } + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "[HEX]", + "code" : "[CODE]", + "nonce" : "[V]", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "[HEX]", + "code" : "0x", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : { + "data" : "[CODE]", + "gasLimit" : "[HEX]", + "gasPrice" : "[V]", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "[HEX]" + } + } +} +)"; diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 3b6cf19c9..1f09ca9fa 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -35,10 +35,12 @@ boost::random::mt19937 RandomCode::gen; boostIntDistrib RandomCode::opCodeDist = boostIntDistrib (0, 255); boostIntDistrib RandomCode::opLengDist = boostIntDistrib (1, 32); boostIntDistrib RandomCode::uniIntDist = boostIntDistrib (0, 0x7fffffff); +boostUint64Distrib RandomCode::uInt64Dist = boostUint64Distrib (0, std::numeric_limits::max()); boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist); boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); +boostUInt64Generator RandomCode::randUInt64Gen = boostUInt64Generator(gen, uInt64Dist); std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType) { @@ -92,7 +94,10 @@ std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options) std::string RandomCode::randomUniIntHex() { refreshSeed(); - return "0x" + toCompactHex((int)randUniIntGen()); + int rand = randUniIntGen() % 100; + if (rand < 50) + return "0x" + toCompactHex((u256)randUniIntGen()); + return "0x" + toCompactHex((u256)randUInt64Gen()); } int RandomCode::randomUniInt() diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 371e40fbf..6a46bbeaf 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -37,9 +37,11 @@ namespace test typedef boost::random::uniform_int_distribution<> boostIntDistrib; typedef boost::random::discrete_distribution<> boostDescreteDistrib; +typedef boost::uniform_int boostUint64Distrib; typedef boost::random::variate_generator boostIntGenerator; typedef boost::random::variate_generator boostWeightGenerator; +typedef boost::random::variate_generator boostUInt64Generator; struct RandomCodeOptions { @@ -73,7 +75,7 @@ public: /// Generate random byte string of a given length static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict); - /// Generate random uniForm Int with reasonable value 0..0x7fffffff + /// Generate random int64 static std::string randomUniIntHex(); static int randomUniInt(); @@ -87,10 +89,12 @@ private: static boostIntDistrib opCodeDist; ///< 0..255 opcodes static boostIntDistrib opLengDist; ///< 1..32 byte string static boostIntDistrib uniIntDist; ///< 0..0x7fffffff + static boostUint64Distrib uInt64Dist; ///< 0..2**64 static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from uniIntDist static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist + static boostUInt64Generator randUInt64Gen; ///< Generate random uInt64 }; } diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index 632e7982b..492bfb746 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -51,9 +51,9 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) } std::cout << " " << i.first << std::endl; - BOOST_REQUIRE(o.count("env") > 0); - BOOST_REQUIRE(o.count("pre") > 0); - BOOST_REQUIRE(o.count("transaction") > 0); + TBOOST_REQUIRE((o.count("env") > 0)); + TBOOST_REQUIRE((o.count("pre") > 0)); + TBOOST_REQUIRE((o.count("transaction") > 0)); ImportTest importer(o, _fillin); @@ -80,13 +80,13 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) #if ETH_FATDB importer.exportTest(output, theState); #else - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off")); + TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off")); #endif } else { - BOOST_REQUIRE(o.count("post") > 0); - BOOST_REQUIRE(o.count("out") > 0); + TBOOST_REQUIRE((o.count("post") > 0)); + TBOOST_REQUIRE((o.count("out") > 0)); // check output checkOutput(output, o); @@ -101,7 +101,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) auto resultAddrs = theState.addresses(); checkAddresses(expectedAddrs, resultAddrs); #endif - BOOST_CHECK_MESSAGE(theState.rootHash() == h256(o["postStateRoot"].get_str()), "wrong post state root"); + TBOOST_CHECK_MESSAGE((theState.rootHash() == h256(o["postStateRoot"].get_str())), "wrong post state root"); } } } From 76a72769f408df1cb3c10a37b3fc200191d19d11 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Fri, 5 Jun 2015 21:43:41 +0300 Subject: [PATCH 056/103] FuzzTesting: VMTests + TransactionTests support --- test/TestHelper.cpp | 33 ++++--- test/TestHelper.h | 13 ++- test/fuzzTesting/CMakeLists.txt | 3 +- test/fuzzTesting/createRandomTest.cpp | 126 ++++++++++++++++++++++++-- test/libevm/vm.cpp | 26 +++--- 5 files changed, 162 insertions(+), 39 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 0e43d278b..743b16273 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -285,9 +285,9 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta #define CHECK(a,b) \ { \ if (_throw == WhenError::Throw) \ - BOOST_CHECK_MESSAGE(a,b); \ + {TBOOST_CHECK_MESSAGE(a,b);}\ else \ - BOOST_WARN_MESSAGE(a,b); \ + {TBOOST_WARN_MESSAGE(a,b);} \ } for (auto const& a: _stateExpect.addresses()) @@ -304,35 +304,35 @@ void ImportTest::checkExpectedState(State const& _stateExpect, State const& _sta } catch(std::out_of_range const&) { - BOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!"); + TBOOST_ERROR("expectedStateOptions map does not match expectedState in checkExpectedState!"); break; } } if (addressOptions.m_bHasBalance) - CHECK(_stateExpect.balance(a.first) == _statePost.balance(a.first), + CHECK((_stateExpect.balance(a.first) == _statePost.balance(a.first)), "Check State: " << a.first << ": incorrect balance " << _statePost.balance(a.first) << ", expected " << _stateExpect.balance(a.first)); if (addressOptions.m_bHasNonce) - CHECK(_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first), + CHECK((_stateExpect.transactionsFrom(a.first) == _statePost.transactionsFrom(a.first)), "Check State: " << a.first << ": incorrect nonce " << _statePost.transactionsFrom(a.first) << ", expected " << _stateExpect.transactionsFrom(a.first)); if (addressOptions.m_bHasStorage) { unordered_map stateStorage = _statePost.storage(a.first); for (auto const& s: _stateExpect.storage(a.first)) - CHECK(stateStorage[s.first] == s.second, + CHECK((stateStorage[s.first] == s.second), "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(stateStorage[s.first]) << ", expected [" << s.first << "] = " << toHex(s.second)); //Check for unexpected storage values stateStorage = _stateExpect.storage(a.first); for (auto const& s: _statePost.storage(a.first)) - CHECK(stateStorage[s.first] == s.second, + CHECK((stateStorage[s.first] == s.second), "Check State: " << a.first << ": incorrect storage [" << s.first << "] = " << toHex(s.second) << ", expected [" << s.first << "] = " << toHex(stateStorage[s.first])); } if (addressOptions.m_bHasCode) - CHECK(_stateExpect.code(a.first) == _statePost.code(a.first), + CHECK((_stateExpect.code(a.first) == _statePost.code(a.first)), "Check State: " << a.first << ": incorrect code '" << toHex(_statePost.code(a.first)) << "', expected '" << toHex(_stateExpect.code(a.first)) << "'"); } } @@ -518,18 +518,17 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o) int j = 0; if (_o["out"].get_str().find("#") == 0) - BOOST_CHECK((u256)_output.size() == toInt(_o["out"].get_str().substr(1))); - + {TBOOST_CHECK(((u256)_output.size() == toInt(_o["out"].get_str().substr(1))));} else if (_o["out"].type() == json_spirit::array_type) for (auto const& d: _o["out"].get_array()) { - BOOST_CHECK_MESSAGE(_output[j] == toInt(d), "Output byte [" << j << "] different!"); + TBOOST_CHECK_MESSAGE((_output[j] == toInt(d)), "Output byte [" << j << "] different!"); ++j; } else if (_o["out"].get_str().find("0x") == 0) - BOOST_CHECK(_output == fromHex(_o["out"].get_str().substr(2))); + {TBOOST_CHECK((_output == fromHex(_o["out"].get_str().substr(2))));} else - BOOST_CHECK(_output == fromHex(_o["out"].get_str())); + TBOOST_CHECK((_output == fromHex(_o["out"].get_str()))); } void checkStorage(map _expectedStore, map _resultStore, Address _expectedAddr) @@ -557,13 +556,13 @@ void checkStorage(map _expectedStore, map _resultStore, void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs) { - BOOST_REQUIRE_EQUAL(_resultLogs.size(), _expectedLogs.size()); + TBOOST_REQUIRE_EQUAL(_resultLogs.size(), _expectedLogs.size()); for (size_t i = 0; i < _resultLogs.size(); ++i) { - BOOST_CHECK_EQUAL(_resultLogs[i].address, _expectedLogs[i].address); - BOOST_CHECK_EQUAL(_resultLogs[i].topics, _expectedLogs[i].topics); - BOOST_CHECK(_resultLogs[i].data == _expectedLogs[i].data); + TBOOST_CHECK_EQUAL(_resultLogs[i].address, _expectedLogs[i].address); + TBOOST_CHECK_EQUAL(_resultLogs[i].topics, _expectedLogs[i].topics); + TBOOST_CHECK((_resultLogs[i].data == _expectedLogs[i].data)); } } diff --git a/test/TestHelper.h b/test/TestHelper.h index df74c2dc3..b1ad923a7 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -35,13 +35,21 @@ #ifdef DONTUSE_BOOST_MACROS #define TBOOST_THROW_EXCEPTION(arg) throw dev::Exception(); #define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception(); + #define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); + #define TBOOST_CHECK_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); + #define TBOOST_CHECK(arg) if(arg == false) throw dev::Exception(); #define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw dev::Exception(); #define TBOOST_WARN_MESSAGE(arg1, arg2) throw dev::Exception(); + #define TBOOST_ERROR(arg) throw dev::Exception(); #else #define TBOOST_THROW_EXCEPTION(arg) BOOST_THROW_EXCEPTION(arg) #define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg) + #define TBOOST_REQUIRE_EQUAL(arg1, arg2) BOOST_REQUIRE_EQUAL(arg1, arg2) + #define TBOOST_CHECK(arg) BOOOST_CHECK(arg) + #define TBOOST_CHECK_EQUAL(arg1, arg2) BOOST_CHECK_EQUAL(arg1, arg2) #define TBOOST_CHECK_MESSAGE(arg1, arg2) BOOST_CHECK_MESSAGE(arg1, arg2) #define TBOOST_WARN_MESSAGE(arg1, arg2) BOOST_WARN_MESSAGE(arg1, arg2) + #define TBOOST_ERROR(arg) BOOST_ERROR(arg) #endif namespace dev @@ -179,6 +187,7 @@ json_spirit::mObject fillJsonWithTransaction(eth::Transaction _txn); //Fill Test Functions void doTransactionTests(json_spirit::mValue& _v, bool _fillin); void doStateTests(json_spirit::mValue& v, bool _fillin); +void doVMTests(json_spirit::mValue& v, bool _fillin); template void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) @@ -188,9 +197,9 @@ void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) auto& resultAddr = resultPair.first; auto expectedAddrIt = _expectedAddrs.find(resultAddr); if (expectedAddrIt == _expectedAddrs.end()) - BOOST_ERROR("Missing result address " << resultAddr); + TBOOST_ERROR("Missing result address " << resultAddr); } - BOOST_CHECK(_expectedAddrs == _resultAddrs); + TBOOST_CHECK((_expectedAddrs == _resultAddrs)); } class Options diff --git a/test/fuzzTesting/CMakeLists.txt b/test/fuzzTesting/CMakeLists.txt index f25a2b31e..9cdc7eb60 100644 --- a/test/fuzzTesting/CMakeLists.txt +++ b/test/fuzzTesting/CMakeLists.txt @@ -8,7 +8,8 @@ include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp") +add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp" "../libevm/vm.cpp") + add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp") add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp" ) diff --git a/test/fuzzTesting/createRandomTest.cpp b/test/fuzzTesting/createRandomTest.cpp index 373207f44..a42ead3ef 100644 --- a/test/fuzzTesting/createRandomTest.cpp +++ b/test/fuzzTesting/createRandomTest.cpp @@ -19,18 +19,23 @@ * @date 2015 */ +///This file require #define DONTUSE_BOOST_MACROS compile flag to run! + #include #include #include #include +#include //String Variables extern std::string const c_testExampleStateTest; extern std::string const c_testExampleTransactionTest; +extern std::string const c_testExampleVMTest; //Main Test functinos void fillRandomTest(std::function doTests, std::string const& testString); +int checkRandomTest(std::function doTests, json_spirit::mValue& value); //Helper Functions std::vector getTypes(); @@ -39,35 +44,111 @@ void parseTestWithTypes(std::string& test); int main(int argc, char *argv[]) { std::string testSuite; + json_spirit::mValue testValue; + bool checktest = false; for (auto i = 0; i < argc; ++i) { auto arg = std::string{argv[i]}; dev::test::Options& options = const_cast(dev::test::Options::get()); if (arg == "--fulloutput") options.fulloutput = true; + else if (arg == "-t" && i + 1 < argc) { testSuite = argv[i + 1]; - if (testSuite != "BlockChainTests" && testSuite != "TransactionTests" && testSuite != "StateTests") + if (testSuite != "BlockChainTests" && testSuite != "TransactionTests" && testSuite != "StateTests" && testSuite != "VMTests") testSuite = ""; } + else + if (arg == "-checktest" && i + 1 < argc) + { + std::string s; + for (int j = i+1; j < argc; ++j) + s += argv[j]; + if (asserts(s.length() > 0)) + { + std::cout << "Error! Content of argument is empty! (Usage -checktest textstream) \n"; + return 1; + } + read_string(s, testValue); + checktest = true; + } } if (testSuite == "") + { std::cout << "Error! Test suite not supported! (Usage -t TestSuite)"; + return 1; + } else if (testSuite == "BlockChainTests") - fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); + { + if (checktest) + return checkRandomTest(dev::test::doTransactionTests, testValue); + else + fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); + } else if (testSuite == "TransactionTests") - fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); + { + if (checktest) + return checkRandomTest(dev::test::doTransactionTests, testValue); + else + fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); + } else if (testSuite == "StateTests") - fillRandomTest(dev::test::doStateTests, c_testExampleStateTest); + { + if (checktest) + return checkRandomTest(dev::test::doStateTests, testValue); + else + fillRandomTest(dev::test::doStateTests, c_testExampleStateTest); + } + else + if (testSuite == "VMTests") + { + if (checktest) + { + dev::eth::VMFactory::setKind(dev::eth::VMKind::JIT); + return checkRandomTest(dev::test::doVMTests, testValue); + } + else + fillRandomTest(dev::test::doVMTests, c_testExampleVMTest); + } return 0; } +int checkRandomTest(std::function doTests, json_spirit::mValue& value) +{ + bool ret = 0; + try + { + //redirect all output to the stream + std::ostringstream strCout; + std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); + std::cout.rdbuf( strCout.rdbuf() ); + std::cerr.rdbuf( strCout.rdbuf() ); + + doTests(value, false); + + //restroe output + std::cout.rdbuf(oldCoutStreamBuf); + std::cerr.rdbuf(oldCoutStreamBuf); + } + catch (dev::Exception const& _e) + { + std::cout << "Failed test with Exception: " << diagnostic_information(_e) << std::endl; + ret = 1; + } + catch (std::exception const& _e) + { + std::cout << "Failed test with Exception: " << _e.what() << std::endl; + ret = 1; + } + return ret; +} + void fillRandomTest(std::function doTests, std::string const& testString) { //redirect all output to the stream @@ -107,6 +188,7 @@ void parseTestWithTypes(std::string& _test) options.addAddress(dev::Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")); options.addAddress(dev::Address("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); options.addAddress(dev::Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")); + options.addAddress(dev::Address("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")); options.addAddress(dev::Address("0x0000000000000000000000000000000000000001")); options.addAddress(dev::Address("0x0000000000000000000000000000000000000002")); options.addAddress(dev::Address("0x0000000000000000000000000000000000000003")); @@ -138,10 +220,10 @@ void parseTestWithTypes(std::string& _test) { int random = dev::test::RandomCode::randomUniInt() % 100; if (random < 30) - _test.replace(pos, 3, "28"); + _test.replace(pos, 3, "0x1c"); else if (random < 60) - _test.replace(pos, 3, "29"); + _test.replace(pos, 3, "0x1d"); else _test.replace(pos, 3, "0x" + dev::test::RandomCode::rndByteSequence(1)); } @@ -221,3 +303,35 @@ std::string const c_testExampleStateTest = R"( } } )"; + +std::string const c_testExampleVMTest = R"( +{ + "randomVMTest": { + "env" : { + "previousHash" : "[HASH32]", + "currentNumber" : "[HEX]", + "currentGasLimit" : "[HEX]", + "currentDifficulty" : "[HEX]", + "currentTimestamp" : "[HEX]", + "currentCoinbase" : "[HASH20]" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "[HEX]", + "nonce" : "[HEX]", + "code" : "[CODE]", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "[HASH20]", + "caller" : "[HASH20]", + "value" : "[HEX]", + "data" : "[CODE]", + "gasPrice" : "[V]", + "gas" : "[HEX]" + } + } +} +)"; diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index ea9339f05..25ed8113b 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -306,9 +306,9 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) } std::cout << " " << i.first << "\n"; - BOOST_REQUIRE(o.count("env") > 0); - BOOST_REQUIRE(o.count("pre") > 0); - BOOST_REQUIRE(o.count("exec") > 0); + TBOOST_REQUIRE((o.count("env") > 0)); + TBOOST_REQUIRE((o.count("pre") > 0)); + TBOOST_REQUIRE((o.count("exec") > 0)); FakeExtVM fev; fev.importEnv(o["env"].get_obj()); @@ -344,12 +344,12 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) catch (Exception const& _e) { cnote << "VM did throw an exception: " << diagnostic_information(_e); - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); + TBOOST_ERROR("Failed VM Test with Exception: " << _e.what()); } catch (std::exception const& _e) { cnote << "VM did throw an exception: " << _e.what(); - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); + TBOOST_ERROR("Failed VM Test with Exception: " << _e.what()); } // delete null entries in storage for the sake of comparison @@ -410,13 +410,13 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) { if (o.count("post") > 0) // No exceptions expected { - BOOST_CHECK(!vmExceptionOccured); + TBOOST_CHECK(!vmExceptionOccured); - BOOST_REQUIRE(o.count("post") > 0); - BOOST_REQUIRE(o.count("callcreates") > 0); - BOOST_REQUIRE(o.count("out") > 0); - BOOST_REQUIRE(o.count("gas") > 0); - BOOST_REQUIRE(o.count("logs") > 0); + TBOOST_REQUIRE((o.count("post") > 0)); + TBOOST_REQUIRE((o.count("callcreates") > 0)); + TBOOST_REQUIRE((o.count("out") > 0)); + TBOOST_REQUIRE((o.count("gas") > 0)); + TBOOST_REQUIRE((o.count("logs") > 0)); dev::test::FakeExtVM test; test.importState(o["post"].get_obj()); @@ -425,7 +425,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkOutput(output, o); - BOOST_CHECK_EQUAL(toInt(o["gas"]), fev.gas); + TBOOST_CHECK_EQUAL(toInt(o["gas"]), fev.gas); State postState, expectState; mObject mPostState = fev.exportState(); @@ -435,7 +435,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkAddresses, bytes> > >(test.addresses, fev.addresses); - checkCallCreates(test.callcreates, fev.callcreates); + checkCallCreates(fev.callcreates, test.callcreates); checkLog(fev.sub.logs, test.sub.logs); } From 5a0f9900677742447e448ab4c7f8112425e262b8 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 9 Jun 2015 18:52:18 +0300 Subject: [PATCH 057/103] Fuzz Tests update --- test/TestHelper.h | 2 +- test/fuzzTesting/fuzzHelper.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/TestHelper.h b/test/TestHelper.h index b1ad923a7..c97d4c017 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -45,7 +45,7 @@ #define TBOOST_THROW_EXCEPTION(arg) BOOST_THROW_EXCEPTION(arg) #define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg) #define TBOOST_REQUIRE_EQUAL(arg1, arg2) BOOST_REQUIRE_EQUAL(arg1, arg2) - #define TBOOST_CHECK(arg) BOOOST_CHECK(arg) + #define TBOOST_CHECK(arg) BOOST_CHECK(arg) #define TBOOST_CHECK_EQUAL(arg1, arg2) BOOST_CHECK_EQUAL(arg1, arg2) #define TBOOST_CHECK_MESSAGE(arg1, arg2) BOOST_CHECK_MESSAGE(arg1, arg2) #define TBOOST_WARN_MESSAGE(arg1, arg2) BOOST_WARN_MESSAGE(arg1, arg2) diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 1f09ca9fa..60d93caf0 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -50,7 +50,7 @@ std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType) for (auto i = 0; i < _length; i++) { uint8_t byte = randOpCodeGen(); - hash += toCompactHex(byte); + hash += toCompactHex(byte, HexPrefix::DontAdd, 1); } return hash; } From 7db380d341e3edfa6db009362659f9a10f0f51eb Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 17 Jun 2015 17:01:25 +0300 Subject: [PATCH 058/103] FuzzTests: blocktests (before merge) --- test/TestHelper.h | 1 + test/fuzzTesting/CMakeLists.txt | 2 +- test/fuzzTesting/createRandomTest.cpp | 93 +++++++++++++++---- test/fuzzTesting/fuzzHelper.cpp | 8 +- test/fuzzTesting/fuzzHelper.h | 2 +- test/libethereum/blockchain.cpp | 128 +++++++++++++------------- 6 files changed, 149 insertions(+), 85 deletions(-) diff --git a/test/TestHelper.h b/test/TestHelper.h index c97d4c017..42f85a82c 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -188,6 +188,7 @@ json_spirit::mObject fillJsonWithTransaction(eth::Transaction _txn); void doTransactionTests(json_spirit::mValue& _v, bool _fillin); void doStateTests(json_spirit::mValue& v, bool _fillin); void doVMTests(json_spirit::mValue& v, bool _fillin); +void doBlockchainTests(json_spirit::mValue& _v, bool _fillin); template void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) diff --git a/test/fuzzTesting/CMakeLists.txt b/test/fuzzTesting/CMakeLists.txt index 9cdc7eb60..9bd2b5540 100644 --- a/test/fuzzTesting/CMakeLists.txt +++ b/test/fuzzTesting/CMakeLists.txt @@ -8,7 +8,7 @@ include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp" "../libevm/vm.cpp") +add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp" "../libethereum/state.cpp" "../libevm/vm.cpp" "../libethereum/blockchain.cpp") add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp") diff --git a/test/fuzzTesting/createRandomTest.cpp b/test/fuzzTesting/createRandomTest.cpp index a42ead3ef..34f90533f 100644 --- a/test/fuzzTesting/createRandomTest.cpp +++ b/test/fuzzTesting/createRandomTest.cpp @@ -27,11 +27,13 @@ #include #include #include +#include //String Variables extern std::string const c_testExampleStateTest; extern std::string const c_testExampleTransactionTest; extern std::string const c_testExampleVMTest; +extern std::string const c_testExampleBlockchainTest; //Main Test functinos void fillRandomTest(std::function doTests, std::string const& testString); @@ -44,7 +46,7 @@ void parseTestWithTypes(std::string& test); int main(int argc, char *argv[]) { std::string testSuite; - json_spirit::mValue testValue; + json_spirit::mValue testmValue; bool checktest = false; for (auto i = 0; i < argc; ++i) { @@ -70,7 +72,7 @@ int main(int argc, char *argv[]) std::cout << "Error! Content of argument is empty! (Usage -checktest textstream) \n"; return 1; } - read_string(s, testValue); + read_string(s, testmValue); checktest = true; } } @@ -84,15 +86,15 @@ int main(int argc, char *argv[]) if (testSuite == "BlockChainTests") { if (checktest) - return checkRandomTest(dev::test::doTransactionTests, testValue); + return checkRandomTest(dev::test::doBlockchainTests, testmValue); else - fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); + fillRandomTest(dev::test::doBlockchainTests, c_testExampleBlockchainTest); } else if (testSuite == "TransactionTests") { if (checktest) - return checkRandomTest(dev::test::doTransactionTests, testValue); + return checkRandomTest(dev::test::doTransactionTests, testmValue); else fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); } @@ -100,7 +102,7 @@ int main(int argc, char *argv[]) if (testSuite == "StateTests") { if (checktest) - return checkRandomTest(dev::test::doStateTests, testValue); + return checkRandomTest(dev::test::doStateTests, testmValue); else fillRandomTest(dev::test::doStateTests, c_testExampleStateTest); } @@ -110,7 +112,7 @@ int main(int argc, char *argv[]) if (checktest) { dev::eth::VMFactory::setKind(dev::eth::VMKind::JIT); - return checkRandomTest(dev::test::doVMTests, testValue); + return checkRandomTest(dev::test::doVMTests, testmValue); } else fillRandomTest(dev::test::doVMTests, c_testExampleVMTest); @@ -152,16 +154,17 @@ int checkRandomTest(std::function doTests, jso void fillRandomTest(std::function doTests, std::string const& testString) { //redirect all output to the stream - std::ostringstream strCout; - std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); - std::cout.rdbuf( strCout.rdbuf() ); - std::cerr.rdbuf( strCout.rdbuf() ); + //std::ostringstream strCout; + //std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); + //std::cout.rdbuf( strCout.rdbuf() ); + //std::cerr.rdbuf( strCout.rdbuf() ); json_spirit::mValue v; try { std::string newTest = testString; parseTestWithTypes(newTest); + std::cout << newTest; json_spirit::read_string(newTest, v); doTests(v, true); } @@ -171,8 +174,8 @@ void fillRandomTest(std::function doTests, std } //restroe output - std::cout.rdbuf(oldCoutStreamBuf); - std::cerr.rdbuf(oldCoutStreamBuf); + //std::cout.rdbuf(oldCoutStreamBuf); + //std::cerr.rdbuf(oldCoutStreamBuf); std::cout << json_spirit::write_string(v, true); } @@ -207,6 +210,9 @@ void parseTestWithTypes(std::string& _test) if (types.at(i) == "[HEX]") _test.replace(pos, 5, dev::test::RandomCode::randomUniIntHex()); else + if (types.at(i) == "[GASLIMIT]") + _test.replace(pos, 10, dev::test::RandomCode::randomUniIntHex(dev::u256("3000000000"))); + else if (types.at(i) == "[HASH20]") _test.replace(pos, 8, dev::test::RandomCode::rndByteSequence(20)); else @@ -235,7 +241,7 @@ void parseTestWithTypes(std::string& _test) std::vector getTypes() { - return {"[CODE]", "[HEX]", "[HASH20]", "[HASH32]", "[0xHASH32]", "[V]"}; + return {"[CODE]", "[HEX]", "[HASH20]", "[HASH32]", "[0xHASH32]", "[V]", "[GASLIMIT]"}; } std::string const c_testExampleTransactionTest = R"( @@ -263,7 +269,7 @@ std::string const c_testExampleStateTest = R"( "env" : { "currentCoinbase" : "[HASH20]", "currentDifficulty" : "[HEX]", - "currentGasLimit" : "[HEX]", + "currentGasLimit" : "[GASLIMIT]", "currentNumber" : "[HEX]", "currentTimestamp" : "[HEX]", "previousHash" : "[HASH32]" @@ -310,7 +316,7 @@ std::string const c_testExampleVMTest = R"( "env" : { "previousHash" : "[HASH32]", "currentNumber" : "[HEX]", - "currentGasLimit" : "[HEX]", + "currentGasLimit" : "[GASLIMIT]", "currentDifficulty" : "[HEX]", "currentTimestamp" : "[HEX]", "currentCoinbase" : "[HASH20]" @@ -335,3 +341,58 @@ std::string const c_testExampleVMTest = R"( } } )"; + +std::string const c_testExampleBlockchainTest = R"( +{ + "blockTest" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "[HASH20]", + "difficulty" : "131072", + "extraData" : "[CODE]", + "gasLimit" : "3141592", + "gasUsed" : "0", + "mixHash" : "[0xHASH32]", + "nonce" : "0x0102030405060708", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "[0xHASH32]", + "stateRoot" : "[0xHASH32]", + "timestamp" : "[HEX]", + "transactionsTrie" : "[0xHASH32]", + "uncleHash" : "[0xHASH32]" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "[HEX]", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "[HEX]", + "nonce" : "[HEX]", + "code" : "[CODE]", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "[CODE]", + "gasLimit" : "[HEX]", + "gasPrice" : "[V]", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "[V]" + } + ], + "uncleHeaders" : [ + ] + } + ] + } +} +)"; diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 60d93caf0..8e03bd767 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -91,13 +91,15 @@ std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options) return code; } -std::string RandomCode::randomUniIntHex() +std::string RandomCode::randomUniIntHex(u256 _maxVal) { + if (_maxVal == 0) + _maxVal = std::numeric_limits::max(); refreshSeed(); int rand = randUniIntGen() % 100; if (rand < 50) - return "0x" + toCompactHex((u256)randUniIntGen()); - return "0x" + toCompactHex((u256)randUInt64Gen()); + return "0x" + toCompactHex((u256)randUniIntGen() % _maxVal); + return "0x" + toCompactHex((u256)randUInt64Gen() % _maxVal); } int RandomCode::randomUniInt() diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 6a46bbeaf..309037e3d 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -76,7 +76,7 @@ public: static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict); /// Generate random int64 - static std::string randomUniIntHex(); + static std::string randomUniIntHex(u256 _maxVal = 0); static int randomUniInt(); private: diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 2c4a0b498..88c39442b 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -59,10 +59,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } cerr << i.first << endl; - BOOST_REQUIRE(o.count("genesisBlockHeader")); + TBOOST_REQUIRE(o.count("genesisBlockHeader")); BlockInfo biGenesisBlock = constructBlock(o["genesisBlockHeader"].get_obj()); - BOOST_REQUIRE(o.count("pre")); + TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); @@ -77,7 +77,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (_fillin) biGenesisBlock.stateRoot = trueState.rootHash(); else - BOOST_CHECK_MESSAGE(biGenesisBlock.stateRoot == trueState.rootHash(), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -99,7 +99,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (_fillin) { - BOOST_REQUIRE(o.count("blocks")); + TBOOST_REQUIRE(o.count("blocks")); mArray blArray; blockSet genesis; @@ -145,7 +145,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // get txs TransactionQueue txs; ZeroGasPricer gp; - BOOST_REQUIRE(blObj.count("transactions")); + TBOOST_REQUIRE(blObj.count("transactions")); for (auto const& txObj: blObj["transactions"].get_array()) { mObject tx = txObj.get_obj(); @@ -337,29 +337,29 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) catch (Exception const& _e) { cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e); - BOOST_CHECK(blObj.count("blockHeader") == 0); - BOOST_CHECK(blObj.count("transactions") == 0); - BOOST_CHECK(blObj.count("uncleHeaders") == 0); + TBOOST_CHECK((blObj.count("blockHeader") == 0)); + TBOOST_CHECK((blObj.count("transactions") == 0)); + TBOOST_CHECK((blObj.count("uncleHeaders") == 0)); continue; } catch (std::exception const& _e) { cnote << "state sync or block import did throw an exception: " << _e.what(); - BOOST_CHECK(blObj.count("blockHeader") == 0); - BOOST_CHECK(blObj.count("transactions") == 0); - BOOST_CHECK(blObj.count("uncleHeaders") == 0); + TBOOST_CHECK((blObj.count("blockHeader") == 0)); + TBOOST_CHECK((blObj.count("transactions") == 0)); + TBOOST_CHECK((blObj.count("uncleHeaders") == 0)); continue; } catch (...) { cnote << "state sync or block import did throw an exception\n"; - BOOST_CHECK(blObj.count("blockHeader") == 0); - BOOST_CHECK(blObj.count("transactions") == 0); - BOOST_CHECK(blObj.count("uncleHeaders") == 0); + TBOOST_CHECK((blObj.count("blockHeader") == 0)); + TBOOST_CHECK((blObj.count("transactions") == 0)); + TBOOST_CHECK((blObj.count("uncleHeaders") == 0)); continue; } - BOOST_REQUIRE(blObj.count("blockHeader")); + TBOOST_REQUIRE(blObj.count("blockHeader")); mObject tObj = blObj["blockHeader"].get_obj(); BlockInfo blockHeaderFromFields; @@ -372,24 +372,24 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (importedAndBest) { //Check the fields restored from RLP to original fields - BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.mixHash == blockFromRlp.mixHash, "mixHash in given RLP not matching the block mixHash!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); - - BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); + + TBOOST_CHECK_MESSAGE((blockHeaderFromFields == blockFromRlp), "However, blockHeaderFromFields != blockFromRlp!"); //Check transaction list @@ -399,15 +399,15 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { mObject tx = txObj.get_obj(); - BOOST_REQUIRE(tx.count("nonce")); - BOOST_REQUIRE(tx.count("gasPrice")); - BOOST_REQUIRE(tx.count("gasLimit")); - BOOST_REQUIRE(tx.count("to")); - BOOST_REQUIRE(tx.count("value")); - BOOST_REQUIRE(tx.count("v")); - BOOST_REQUIRE(tx.count("r")); - BOOST_REQUIRE(tx.count("s")); - BOOST_REQUIRE(tx.count("data")); + TBOOST_REQUIRE(tx.count("nonce")); + TBOOST_REQUIRE(tx.count("gasPrice")); + TBOOST_REQUIRE(tx.count("gasLimit")); + TBOOST_REQUIRE(tx.count("to")); + TBOOST_REQUIRE(tx.count("value")); + TBOOST_REQUIRE(tx.count("v")); + TBOOST_REQUIRE(tx.count("r")); + TBOOST_REQUIRE(tx.count("s")); + TBOOST_REQUIRE(tx.count("data")); try { @@ -416,7 +416,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } catch (Exception const& _e) { - BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e)); + TBOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e)); } catch (exception const& _e) { @@ -432,22 +432,22 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) txsFromRlp.push_back(tx); } - BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match"); + TBOOST_CHECK_MESSAGE((txsFromRlp.size() == txsFromField.size()), "transaction list size does not match"); for (size_t i = 0; i < txsFromField.size(); ++i) { - BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match"); - - BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions from rlp and transaction from field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].data() == txsFromRlp[i].data()), "transaction data in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].gas() == txsFromRlp[i].gas()), "transaction gasLimit in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice()), "transaction gasPrice in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].nonce() == txsFromRlp[i].nonce()), "transaction nonce in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].signature().r == txsFromRlp[i].signature().r), "transaction r in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].signature().s == txsFromRlp[i].signature().s), "transaction s in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].signature().v == txsFromRlp[i].signature().v), "transaction v in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress()), "transaction receiveAddress in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].value() == txsFromRlp[i].value()), "transaction receiveAddress in rlp and in field do not match"); + + TBOOST_CHECK_MESSAGE((txsFromField[i] == txsFromRlp[i]), "transactions from rlp and transaction from field do not match"); + TBOOST_CHECK_MESSAGE((txsFromField[i].rlp() == txsFromRlp[i].rlp()), "transactions rlp do not match"); } // check uncle list @@ -458,7 +458,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) for (auto const& uBlHeaderObj: blObj["uncleHeaders"].get_array()) { mObject uBlH = uBlHeaderObj.get_obj(); - BOOST_REQUIRE(uBlH.size() == 16); + TBOOST_REQUIRE((uBlH.size() == 16)); bytes uncleRLP = createBlockRLPFromFields(uBlH); const RLP c_uRLP(uncleRLP); BlockInfo uncleBlockHeader; @@ -468,7 +468,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) } catch(...) { - BOOST_ERROR("invalid uncle header"); + TBOOST_ERROR("invalid uncle header"); } uBlHsFromField.push_back(uncleBlockHeader); } @@ -482,15 +482,15 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) uBlHsFromRlp.push_back(uBl); } - BOOST_REQUIRE_EQUAL(uBlHsFromField.size(), uBlHsFromRlp.size()); + TBOOST_REQUIRE_EQUAL(uBlHsFromField.size(), uBlHsFromRlp.size()); for (size_t i = 0; i < uBlHsFromField.size(); ++i) - BOOST_CHECK_MESSAGE(uBlHsFromField[i] == uBlHsFromRlp[i], "block header in rlp and in field do not match"); + TBOOST_CHECK_MESSAGE((uBlHsFromField[i] == uBlHsFromRlp[i]), "block header in rlp and in field do not match"); }//importedAndBest }//all blocks - BOOST_REQUIRE(o.count("lastblockhash") > 0); - BOOST_CHECK_MESSAGE(toString(trueBc.info().hash()) == o["lastblockhash"].get_str(), + TBOOST_REQUIRE((o.count("lastblockhash") > 0)); + TBOOST_CHECK_MESSAGE((toString(trueBc.info().hash()) == o["lastblockhash"].get_str()), "Boost check: " + i.first + " lastblockhash does not match " + toString(trueBc.info().hash()) + " expected: " + o["lastblockhash"].get_str()); } } @@ -713,11 +713,11 @@ BlockInfo constructBlock(mObject& _o) } catch (std::exception const& _e) { - BOOST_ERROR("Failed block population with Exception: " << _e.what()); + TBOOST_ERROR("Failed block population with Exception: " << _e.what()); } catch(...) { - BOOST_ERROR("block population did throw an unknown exception\n"); + TBOOST_ERROR("block population did throw an unknown exception\n"); } return ret; } From cbe3f80d6f28a1af1a8c8fed52a9d2d492153e4e Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 17 Jun 2015 16:23:28 +0200 Subject: [PATCH 059/103] - bug fix with encoding bytes and string. - bug fix when using String type QML control - bytes parameter: stop trying to get ASCII value (as String as been reimported) --- mix/ContractCallDataEncoder.cpp | 36 +++++++++++++-------------------- mix/QVariableDeclaration.h | 1 + mix/qml/QIntTypeView.qml | 3 --- mix/qml/QStringTypeView.qml | 33 +++++++++++++----------------- mix/qml/StructView.qml | 2 +- mix/qml/js/InputValidator.js | 19 ++++------------- 6 files changed, 34 insertions(+), 60 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index a1aae3f79..3c635b8b0 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -97,37 +97,34 @@ void ContractCallDataEncoder::encodeArray(QJsonArray const& _array, QList _ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& _type) { - QStringList strList; - if (_type.array) + if (_type.dynamicSize && (_type.type == SolidityType::Type::Bytes || _type.type == SolidityType::Type::String)) + { + bytes empty(32); + size_t sizePos = m_dynamicData.size(); + m_dynamicData += empty; //reserve space for count + u256 count = encodeSingleItem(_data.toString(), _type, m_dynamicData); + vector_ref sizeRef(m_dynamicData.data() + sizePos, 32); + toBigEndian(count, sizeRef); + m_staticOffsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); + m_encodedData += empty; //reserve space for offset + } + else if (_type.array) { QList dim = extractDimension(_type. name); bytes content; - QJsonDocument jsonResponse = QJsonDocument::fromJson(_data.toString().toUtf8()); - QJsonArray jsonObject = jsonResponse.array(); size_t size = m_encodedData.size(); - if (dim[0] == -1) + if (dim.front() == -1) { m_encodedData += bytes(32); // reserve space for offset m_staticOffsetMap.push_back(std::make_pair(size, m_dynamicData.size())); } - encodeArray(jsonObject, dim, _type, content); + encodeArray(_data.toJsonArray(), dim, _type, content); if (!_type.dynamicSize) m_encodedData.insert(m_encodedData.end(), content.begin(), content.end()); else m_dynamicData.insert(m_dynamicData.end(), content.begin(), content.end()); } - else if (_type.dynamicSize && _type.type == SolidityType::Type::Bytes) - { - bytes empty(32); - size_t sizePos = m_dynamicData.size(); - m_dynamicData += empty; //reserve space for count - u256 count = encodeSingleItem(_data.toString(), _type, m_dynamicData); - vector_ref sizeRef(m_dynamicData.data() + sizePos, 32); - toBigEndian(count, sizeRef); - m_staticOffsetMap.push_back(std::make_pair(m_encodedData.size(), sizePos)); - m_encodedData += empty; //reserve space for offset - } else encodeSingleItem(_data.toString(), _type, m_encodedData); } @@ -179,11 +176,6 @@ unsigned ContractCallDataEncoder::encodeSingleItem(QString const& _data, Solidit catch (std::exception const&) { // manage input as a string. - QRegExp strExtract("\"(.*)\""); //check if contains both string and hex value, keep the string. - int i = strExtract.indexIn(src); - if (i != -1) - src = strExtract.cap(0); - src = src.replace("\"", ""); result = encodeStringParam(src, alignSize); } } diff --git a/mix/QVariableDeclaration.h b/mix/QVariableDeclaration.h index 85c719987..583847b44 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -60,6 +60,7 @@ public: Bool, Address, Bytes, + String, Enum, Struct }; diff --git a/mix/qml/QIntTypeView.qml b/mix/qml/QIntTypeView.qml index c42e65654..ec54d6409 100644 --- a/mix/qml/QIntTypeView.qml +++ b/mix/qml/QIntTypeView.qml @@ -33,6 +33,3 @@ Item } } } - - - diff --git a/mix/qml/QStringTypeView.qml b/mix/qml/QStringTypeView.qml index 101863421..c42e65654 100644 --- a/mix/qml/QStringTypeView.qml +++ b/mix/qml/QStringTypeView.qml @@ -2,38 +2,33 @@ import QtQuick 2.0 Item { - property string value + property alias value: textinput.text property alias readOnly: textinput.readOnly id: editRoot - height: 20 width: readOnly ? textinput.implicitWidth : 150 - onValueChanged: - { - textinput.text = value - } - SourceSansProBold - { - id: boldFont + DebuggerPaneStyle { + id: dbgStyle } Rectangle { anchors.fill: parent radius: 4 TextInput { + anchors.verticalCenter: parent.verticalCenter id: textinput + font.family: dbgStyle.general.basicFont clip: true - anchors.fill: parent - wrapMode: Text.WrapAnywhere - font.family: boldFont.name selectByMouse: true - onTextChanged: { - var stringRegEx = new RegExp('"^\\"*', "g") - var str = stringRegEx.exec(text) - if (str && str.length > 0) - value = str[0] - else - value = text + text: value + anchors.fill: parent + font.pointSize: dbgStyle.general.basicFontSize + color: dbgStyle.general.basicColor + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: textinput.forceActiveFocus() } } } diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 880f22057..6b9edc755 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -72,7 +72,7 @@ Column return Qt.createComponent("qrc:/qml/QIntTypeView.qml"); else if (t === QSolidityType.Bool) return Qt.createComponent("qrc:/qml/QBoolTypeView.qml"); - else if (t === QSolidityType.Bytes) + else if (t === QSolidityType.Bytes || t === QSolidityType.String) return Qt.createComponent("qrc:/qml/QStringTypeView.qml"); else if (t === QSolidityType.Hash) return Qt.createComponent("qrc:/qml/QHashTypeView.qml"); diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js index 46b23274d..7190ae291 100644 --- a/mix/qml/js/InputValidator.js +++ b/mix/qml/js/InputValidator.js @@ -1,8 +1,8 @@ Qt.include("QEtherHelper.js") -var nbRegEx = new RegExp('^[0-9]+$'); -var arrayRegEx = new RegExp('\\[[^\\]]*\\]', "g"); -var capturenbRegEx = new RegExp("[0-9]+"); +var nbRegEx; +var arrayRegEx; +var capturenbRegEx; function validate(model, values) { @@ -54,10 +54,7 @@ function check(type, value) function isArray(_type) { - if (!arrayRegEx.test(_type)) - return false - else - return (_type.indexOf("int") !== -1 || _type.indexOf("bytes") !== -1 || _type.indexOf("bool") !== -1 || _type.indexOf("adress") !== -1) + return arrayRegEx.test(_type); } function checkArrayRecursively(_type, _dim, _array) @@ -186,14 +183,6 @@ function validateAddress(_type, _value) function validateBytes(_type, _value) { var ret = { valid: true, message: "" } - if (_value.indexOf("\"") === 0 && _value.indexOf("0x") !== -1) - { - //this is a different fomatting - var stringRegEx = new RegExp('".*"', "g"); - var matches = _value.match(stringRegEx); - if (matches.length === 1) - _value = matches[0] - } if (_type !== "bytes" && _value.length > parseInt(_type.replace("bytes", "")) ) { ret.valid = false; From eac6ed820b573628d715f846cfe725498c8c1bc4 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 17 Jun 2015 16:45:47 +0200 Subject: [PATCH 060/103] hide extractDimension from .h --- mix/ContractCallDataEncoder.cpp | 39 +++++++++++++++++---------------- mix/ContractCallDataEncoder.h | 1 - 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 3c635b8b0..62cc39a04 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -37,6 +37,24 @@ using namespace dev; using namespace dev::solidity; using namespace dev::mix; +static QList extractDimension(QString const& _type) +{ + QList dim; + QRegExp dimExtract("(\\[[^\\]]*\\])"); + int pos = dimExtract.indexIn(_type); + while (pos != -1) + { + QString d = dimExtract.cap(0); + pos += d.length(); + pos = dimExtract.indexIn(_type, pos); + if (d == "[]") + dim.push_front(-1); + else + dim.push_front(d.replace("[", "").replace("]", "").toInt()); + } + return dim; +} + bytes ContractCallDataEncoder::encodedData() { bytes r(m_encodedData); @@ -118,7 +136,8 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& m_encodedData += bytes(32); // reserve space for offset m_staticOffsetMap.push_back(std::make_pair(size, m_dynamicData.size())); } - encodeArray(_data.toJsonArray(), dim, _type, content); + QJsonDocument jsonDoc = QJsonDocument::fromJson(_data.toString().toUtf8()); + encodeArray(jsonDoc.array(), dim, _type, content); if (!_type.dynamicSize) m_encodedData.insert(m_encodedData.end(), content.begin(), content.end()); @@ -129,24 +148,6 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& encodeSingleItem(_data.toString(), _type, m_encodedData); } -QList ContractCallDataEncoder::extractDimension(QString const& _type) -{ - QList dim; - QRegExp dimExtract("(\\[[^\\]]*\\])"); - int pos = dimExtract.indexIn(_type); - while (pos != -1) - { - QString d = dimExtract.cap(0); - pos += d.length(); - pos = dimExtract.indexIn(_type, pos); - if (d == "[]") - dim.push_front(-1); - else - dim.push_front(d.replace("[", "").replace("]", "").toInt()); - } - return dim; -} - unsigned ContractCallDataEncoder::encodeSingleItem(QString const& _data, SolidityType const& _type, bytes& _dest) { if (_type.type == SolidityType::Type::Struct) diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 867e75751..e29cb92e0 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -71,7 +71,6 @@ private: QString toString(bool _b); QString toString(dev::bytes const& _b); bool asString(dev::bytes const& _b, QString& _str); - QList extractDimension(QString const& _type); void encodeArray(QJsonArray const& _array, QList _dim, SolidityType const& _type, bytes& _content); QString toChar(dev::bytes const& _b); From e617bfb0f7b2854acb00ae90afb3f1a223502210 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Jun 2015 17:15:30 +0200 Subject: [PATCH 061/103] Corrected typo about max peer count. --- libp2p/Host.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index a0d8e1297..feb116c4a 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -391,7 +391,7 @@ void Host::runAcceptor() { if (peerCount() > 9 * m_idealPeerCount) { - clog(NetConnect) << "Dropping incoming connect due to maximum peer count (2 * ideal peer count): " << socket->remoteEndpoint(); + clog(NetConnect) << "Dropping incoming connect due to maximum peer count (9 * ideal peer count): " << socket->remoteEndpoint(); socket->close(); if (ec.value() < 1) runAcceptor(); From 2b16073d5b11a004309003cc5dcb12238c5f5fd4 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 17 Jun 2015 18:31:14 +0300 Subject: [PATCH 062/103] FuzzTests: simple block test + NOBOOST flag --- CMakeLists.txt | 5 +++++ test/TestHelper.h | 3 +-- test/fuzzTesting/createRandomTest.cpp | 23 +++++++++++------------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 729f95ed6..904badcf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ option(FATDB "Build with ability to list entries in the Trie. Doubles DB size, s option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF) option(PROFILING "Build in support for profiling" OFF) + set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).") option(MINER "Build the CLI miner component" ON) option(ETHKEY "Build the CLI key manager component" ON) @@ -40,6 +41,7 @@ option(TOOLS "Build the tools components" ON) option(NCURSES "Build the NCurses components" OFF) option(GUI "Build GUI components (AlethZero, Mix)" ON) option(TESTS "Build the tests." ON) +option(NOBOOST "No use of boost macros in test functions" OFF) option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF) option(ETHASHCL "Build in support for GPU mining via OpenCL" OFF) option(JSCONSOLE "Build in javascript console" OFF) @@ -82,6 +84,7 @@ function(configureProject) add_definitions(-DETH_CURL) endif() + add_definitions(-DNOBOOST) add_definitions(-DETH_TRUE) endfunction() @@ -195,6 +198,7 @@ eth_format_option(PROFILING) eth_format_option(SOLIDITY) eth_format_option(GUI) eth_format_option(TESTS) +eth_format_option(NOBOOST) eth_format_option(TOOLS) eth_format_option(ETHASHCL) eth_format_option(JSCONSOLE) @@ -316,6 +320,7 @@ message("-- SERPENT Build Serpent language components ${SERPENT} message("-- GUI Build GUI components ${GUI}") message("-- NCURSES Build NCurses components ${NCURSES}") message("-- TESTS Build tests ${TESTS}") +message("-- NOBOOST No BOOST macros in test functions ${NOBOOST}") message("-- ETHASHCL Build OpenCL components (experimental!) ${ETHASHCL}") message("-- JSCONSOLE Build with javascript console ${JSCONSOLE}") message("-- EVMJIT Build LLVM-based JIT EVM (experimental!) ${EVMJIT}") diff --git a/test/TestHelper.h b/test/TestHelper.h index 42f85a82c..df33c00d8 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -31,8 +31,7 @@ #include #include -#define DONTUSE_BOOST_MACROS -#ifdef DONTUSE_BOOST_MACROS +#ifdef NOBOOST #define TBOOST_THROW_EXCEPTION(arg) throw dev::Exception(); #define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception(); #define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); diff --git a/test/fuzzTesting/createRandomTest.cpp b/test/fuzzTesting/createRandomTest.cpp index 34f90533f..e21f22eea 100644 --- a/test/fuzzTesting/createRandomTest.cpp +++ b/test/fuzzTesting/createRandomTest.cpp @@ -154,17 +154,16 @@ int checkRandomTest(std::function doTests, jso void fillRandomTest(std::function doTests, std::string const& testString) { //redirect all output to the stream - //std::ostringstream strCout; - //std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); - //std::cout.rdbuf( strCout.rdbuf() ); - //std::cerr.rdbuf( strCout.rdbuf() ); + std::ostringstream strCout; + std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); + std::cout.rdbuf( strCout.rdbuf() ); + std::cerr.rdbuf( strCout.rdbuf() ); json_spirit::mValue v; try { std::string newTest = testString; parseTestWithTypes(newTest); - std::cout << newTest; json_spirit::read_string(newTest, v); doTests(v, true); } @@ -174,8 +173,8 @@ void fillRandomTest(std::function doTests, std } //restroe output - //std::cout.rdbuf(oldCoutStreamBuf); - //std::cerr.rdbuf(oldCoutStreamBuf); + std::cout.rdbuf(oldCoutStreamBuf); + std::cerr.rdbuf(oldCoutStreamBuf); std::cout << json_spirit::write_string(v, true); } @@ -246,7 +245,7 @@ std::vector getTypes() std::string const c_testExampleTransactionTest = R"( { -"TransactionTest" : { + "randomTransactionTest" : { "transaction" : { "data" : "[CODE]", @@ -344,7 +343,7 @@ std::string const c_testExampleVMTest = R"( std::string const c_testExampleBlockchainTest = R"( { - "blockTest" : { + "randomBlockTest" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "[HASH20]", @@ -359,8 +358,8 @@ std::string const c_testExampleBlockchainTest = R"( "receiptTrie" : "[0xHASH32]", "stateRoot" : "[0xHASH32]", "timestamp" : "[HEX]", - "transactionsTrie" : "[0xHASH32]", - "uncleHash" : "[0xHASH32]" + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -371,7 +370,7 @@ std::string const c_testExampleBlockchainTest = R"( }, "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "[HEX]", - "nonce" : "[HEX]", + "nonce" : "0", "code" : "[CODE]", "storage": {} } From 5390c358b725a457a54e8c77c714d7f9d159906f Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 17 Jun 2015 17:57:37 +0200 Subject: [PATCH 063/103] OpenCL bin2h script correction - The script to turn the source into a bytearray header is no longer a function but is instead the body of a script so that it's callable as an external cmake command - Spaces -> Tabs in the touched cmake files --- libethash-cl/CMakeLists.txt | 27 +++++----- libethash-cl/bin2h.cmake | 100 +++++++++++++++++------------------- 2 files changed, 62 insertions(+), 65 deletions(-) diff --git a/libethash-cl/CMakeLists.txt b/libethash-cl/CMakeLists.txt index 6533bf794..6da254cfb 100644 --- a/libethash-cl/CMakeLists.txt +++ b/libethash-cl/CMakeLists.txt @@ -1,22 +1,23 @@ set(EXECUTABLE ethash-cl) -include(bin2h.cmake) -bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl - VARIABLE_NAME ethash_cl_miner_kernel - HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) - -# Add a custom command so that the user can regenerate the header file containing the kernel -# code's bytearray by running "make clbin2h" - add_custom_target(clbin2h) - add_custom_command(TARGET clbin2h - PRE_BUILD - COMMAND ${CMAKE_COMMAND} -DBIN2H_SOURCE_FILE="${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl" +# A custom command and target to turn the OpenCL kernel into a byte array header +# The normal build depends on it properly and if the kernel file is changed, then +# a rebuild of libethash-cl should be triggered +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h + COMMAND ${CMAKE_COMMAND} ARGS + -DBIN2H_SOURCE_FILE="${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl" -DBIN2H_VARIABLE_NAME=ethash_cl_miner_kernel -DBIN2H_HEADER_FILE="${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h" - -P "${CMAKE_CURRENT_SOURCE_DIR}/bin2h.cmake") + -P "${CMAKE_CURRENT_SOURCE_DIR}/bin2h.cmake" + COMMENT "Generating OpenCL Kernel Byte Array" + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl +) +add_custom_target(clbin2h DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h ${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl) aux_source_directory(. SRC_LIST) -file(GLOB HEADERS "*.h") +file(GLOB OUR_HEADERS "*.h") +set(HEADERS ${OUR_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${OpenCL_INCLUDE_DIRS}) diff --git a/libethash-cl/bin2h.cmake b/libethash-cl/bin2h.cmake index 90ca9cc5b..27ab4eefa 100644 --- a/libethash-cl/bin2h.cmake +++ b/libethash-cl/bin2h.cmake @@ -6,31 +6,31 @@ include(CMakeParseArguments) # VARIABLE - The name of the CMake variable holding the string. # AT_COLUMN - The column position at which string will be wrapped. function(WRAP_STRING) - set(oneValueArgs VARIABLE AT_COLUMN) - cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) + set(oneValueArgs VARIABLE AT_COLUMN) + cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) - string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) - math(EXPR offset "0") + string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) + math(EXPR offset "0") - while(stringLength GREATER 0) + while(stringLength GREATER 0) - if(stringLength GREATER ${WRAP_STRING_AT_COLUMN}) - math(EXPR length "${WRAP_STRING_AT_COLUMN}") - else() - math(EXPR length "${stringLength}") - endif() + if(stringLength GREATER ${WRAP_STRING_AT_COLUMN}) + math(EXPR length "${WRAP_STRING_AT_COLUMN}") + else() + math(EXPR length "${stringLength}") + endif() - string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) - set(lines "${lines}\n${line}") + string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) + set(lines "${lines}\n${line}") - math(EXPR stringLength "${stringLength} - ${length}") - math(EXPR offset "${offset} + ${length}") - endwhile() + math(EXPR stringLength "${stringLength} - ${length}") + math(EXPR offset "${offset} + ${length}") + endwhile() - set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) + set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) endfunction() -# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file +# Script to embed contents of a file as byte array in C/C++ header file(.h). The header file # will contain a byte array and integer variable holding the size of the array. # Parameters # SOURCE_FILE - The path of source file whose contents will be embedded in the header file. @@ -42,45 +42,41 @@ endfunction() # useful if the source file is a text file and we want to use the file contents # as string. But the size variable holds size of the byte array without this # null byte. -# Usage: -# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG") -function(BIN2H) - set(options APPEND NULL_TERMINATE) - set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE) - cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN}) +set(options APPEND NULL_TERMINATE) +set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE) +# cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN}) - # reads source file contents as hex string - file(READ ${BIN2H_SOURCE_FILE} hexString HEX) - string(LENGTH ${hexString} hexStringLength) +# reads source file contents as hex string +file(READ ${BIN2H_SOURCE_FILE} hexString HEX) +string(LENGTH ${hexString} hexStringLength) - # appends null byte if asked - if(BIN2H_NULL_TERMINATE) - set(hexString "${hexString}00") - endif() +# appends null byte if asked +if(BIN2H_NULL_TERMINATE) + set(hexString "${hexString}00") +endif() - # wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line) - wrap_string(VARIABLE hexString AT_COLUMN 32) - math(EXPR arraySize "${hexStringLength} / 2") +# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line) +wrap_string(VARIABLE hexString AT_COLUMN 32) +math(EXPR arraySize "${hexStringLength} / 2") - # adds '0x' prefix and comma suffix before and after every byte respectively - string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString}) - # removes trailing comma - string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) +# adds '0x' prefix and comma suffix before and after every byte respectively +string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString}) +# removes trailing comma +string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) - # converts the variable name into proper C identifier - IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake - string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) - ENDIF() - string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) +# converts the variable name into proper C identifier +IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake + string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) +ENDIF() +string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) - # declares byte array and the length variables - set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };") - set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};") +# declares byte array and the length variables +set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };") +set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};") - set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n") - if(BIN2H_APPEND) - file(APPEND ${BIN2H_HEADER_FILE} "${declarations}") - else() - file(WRITE ${BIN2H_HEADER_FILE} "${declarations}") - endif() -endfunction() +set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n") +if(BIN2H_APPEND) + file(APPEND ${BIN2H_HEADER_FILE} "${declarations}") +else() + file(WRITE ${BIN2H_HEADER_FILE} "${declarations}") +endif() From faafba12fa4d8696e57760b9367ac80d3d23e94f Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Jun 2015 18:51:29 +0200 Subject: [PATCH 064/103] Storage array reference test. --- test/libsolidity/SolidityEndToEndTest.cpp | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f4d875e77..66a8f8820 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4257,6 +4257,59 @@ BOOST_AUTO_TEST_CASE(return_string) // BOOST_CHECK(callContractFunction("s()") == args); } +BOOST_AUTO_TEST_CASE(storage_array_ref) +{ + char const* sourceCode = R"( + contract BinarySearch { + /// Finds the position of _value in the sorted list _data. + /// Note that "internal" is important here, because storage references only work for internal or private functions + function find(uint[] storage _data, uint _value) internal returns (uint o_position) { + return find(_data, 0, _data.length, _value); + } + function find(uint[] storage _data, uint _begin, uint _len, uint _value) private returns (uint o_position) { + if (_len == 0 || (_len == 1 && _data[_begin] != _value)) + return uint(-1); // failure + uint halfLen = _len / 2; + uint v = _data[_begin + halfLen]; + if (_value < v) + return find(_data, _begin, halfLen, _value); + else if (_value > v) + return find(_data, _begin + halfLen + 1, halfLen - 1, _value); + else + return _begin + halfLen; + } + } + + contract Store is BinarySearch { + uint[] data; + function add(uint v) { + data.length++; + data[data.length - 1] = v; + } + function find(uint v) returns (uint) { + return find(data, v); + } + } + )"; + compileAndRun(sourceCode, 0, "Store"); + BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(-1))); + BOOST_REQUIRE(callContractFunction("add(uint256)", u256(7)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(0))); + BOOST_CHECK(callContractFunction("add(uint256)", u256(11)) == encodeArgs()); + BOOST_CHECK(callContractFunction("add(uint256)", u256(17)) == encodeArgs()); + BOOST_CHECK(callContractFunction("add(uint256)", u256(27)) == encodeArgs()); + BOOST_CHECK(callContractFunction("add(uint256)", u256(31)) == encodeArgs()); + BOOST_CHECK(callContractFunction("add(uint256)", u256(32)) == encodeArgs()); + BOOST_CHECK(callContractFunction("add(uint256)", u256(66)) == encodeArgs()); + BOOST_CHECK(callContractFunction("add(uint256)", u256(177)) == encodeArgs()); + BOOST_CHECK(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(0))); + BOOST_CHECK(callContractFunction("find(uint256)", u256(27)) == encodeArgs(u256(3))); + BOOST_CHECK(callContractFunction("find(uint256)", u256(32)) == encodeArgs(u256(5))); + BOOST_CHECK(callContractFunction("find(uint256)", u256(176)) == encodeArgs(u256(-1))); + BOOST_CHECK(callContractFunction("find(uint256)", u256(0)) == encodeArgs(u256(-1))); + BOOST_CHECK(callContractFunction("find(uint256)", u256(400)) == encodeArgs(u256(-1))); +} + BOOST_AUTO_TEST_SUITE_END() } From 18127c1b4e5df7546b7c18c968c83ee231438006 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Jun 2015 21:23:05 +0200 Subject: [PATCH 065/103] continue syncing refactoring --- libethereum/BlockChainSync.cpp | 510 +++++++++++++++++++-------------- libethereum/BlockChainSync.h | 153 +++++++--- libethereum/BlockQueue.cpp | 31 +- libethereum/BlockQueue.h | 4 + libethereum/EthereumHost.cpp | 5 + libethereum/EthereumHost.h | 1 + libethereum/EthereumPeer.h | 5 +- 7 files changed, 443 insertions(+), 266 deletions(-) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index ed43e0786..64de5f590 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file EthereumHost.cpp +/** @file BlockChainSync.cpp * @author Gav Wood * @date 2014 */ @@ -22,30 +22,32 @@ #include "BlockChainSync.h" #include -#include #include #include #include #include #include #include "BlockChain.h" -#include "TransactionQueue.h" #include "BlockQueue.h" #include "EthereumPeer.h" #include "EthereumHost.h" #include "DownloadMan.h" + using namespace std; using namespace dev; using namespace dev::eth; using namespace p2p; - unsigned const c_chainReorgSize = 30000; - BlockChainSync::BlockChainSync(EthereumHost& _host): m_host(_host) { + m_bqRoomAvailable = host().bq().onRoomAvailable([this]() + { + RecursiveGuard l(x_sync); + continueSync(); + }); } BlockChainSync::~BlockChainSync() @@ -69,9 +71,27 @@ void BlockChainSync::abortSync() downloadMan().resetToChain(h256s()); } -void BlockChainSync::onPeerStatus(EthereumPeer*) +void BlockChainSync::onPeerStatus(EthereumPeer* _peer) { - + RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; + if (_peer->m_genesisHash != host().chain().genesisHash()) + _peer->disable("Invalid genesis hash"); + else if (_peer->m_protocolVersion != host().protocolVersion() && _peer->m_protocolVersion != EthereumHost::c_oldProtocolVersion) + _peer->disable("Invalid protocol version."); + else if (_peer->m_networkId != host().networkId()) + _peer->disable("Invalid network identifier."); + else if (_peer->session()->info().clientVersion.find("/v0.7.0/") != string::npos) + _peer->disable("Blacklisted client version."); + else if (host().isBanned(_peer->session()->id())) + _peer->disable("Peer banned for previous bad behaviour."); + else + { + unsigned estimatedHashes = estimateHashes(); + _peer->m_expectedHashes = estimatedHashes; + onNewPeer(_peer); + } + DEV_INVARIANT_CHECK; } unsigned BlockChainSync::estimateHashes() @@ -88,9 +108,183 @@ unsigned BlockChainSync::estimateHashes() return blockCount; } +void BlockChainSync::requestBlocks(EthereumPeer* _peer) +{ + if (host().bq().knownFull()) + { + clog(NetAllDetail) << "Waiting for block queue before downloading blocks"; + m_lastActiveState = m_state; + pauseSync(); + _peer->setIdle(); + return; + } + _peer->requestBlocks(); + if (_peer->m_asking != Asking::Blocks) //nothing to download + { + peerDoneBlocks(_peer); + if (downloadMan().isComplete()) + completeSync(); + return; + } +} + +void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) +{ + RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; + unsigned itemCount = _r.itemCount(); + clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); + + _peer->setIdle(); + if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks) + clog(NetWarn) << "Unexpected Blocks received!"; + if (m_state == SyncState::Waiting) + { + clog(NetAllDetail) << "Ignored blocks while waiting"; + return; + } + + if (itemCount == 0) + { + // Got to this peer's latest block - just give up. + peerDoneBlocks(_peer); + if (downloadMan().isComplete()) + completeSync(); + return; + } + + unsigned success = 0; + unsigned future = 0; + unsigned unknown = 0; + unsigned got = 0; + unsigned repeated = 0; + u256 maxUnknownNumber = 0; + h256 maxUnknown; + + for (unsigned i = 0; i < itemCount; ++i) + { + auto h = BlockInfo::headerHash(_r[i].data()); + if (_peer->m_sub.noteBlock(h)) + { + _peer->addRating(10); + switch (host().bq().import(_r[i].data(), host().chain())) + { + case ImportResult::Success: + success++; + break; + + case ImportResult::Malformed: + case ImportResult::BadChain: + _peer->disable("Malformed block received."); + return; + + case ImportResult::FutureTimeKnown: + future++; + break; + case ImportResult::AlreadyInChain: + case ImportResult::AlreadyKnown: + got++; + break; + + case ImportResult::FutureTimeUnkwnown: + future++; //Fall through + + case ImportResult::UnknownParent: + { + unknown++; + if (m_state == SyncState::NewBlocks) + { + BlockInfo bi; + bi.populateFromHeader(_r[i][0]); + if (bi.number > maxUnknownNumber) + { + maxUnknownNumber = bi.number; + maxUnknown = h; + } + } + break; + } + + default:; + } + } + else + { + _peer->addRating(0); // -1? + repeated++; + } + } + + clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; + + if (host().bq().unknownFull()) + { + clog(NetWarn) << "Too many unknown blocks, restarting sync"; + restartSync(); + return; + } + + if (m_state == SyncState::NewBlocks && unknown > 0) + resetSyncFor(_peer, maxUnknown, std::numeric_limits::max()); //TODO: proper total difficuty + else if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) + { + if (downloadMan().isComplete()) + completeSync(); + else if (!got) + requestBlocks(_peer); + else + peerDoneBlocks(_peer); + } + DEV_INVARIANT_CHECK; +} + +void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) +{ + DEV_INVARIANT_CHECK; + RecursiveGuard l(x_sync); + auto h = BlockInfo::headerHash(_r[0].data()); + clog(NetMessageSummary) << "NewBlock: " << h; + + if (_r.itemCount() != 2) + _peer->disable("NewBlock without 2 data fields."); + else + { + switch (host().bq().import(_r[0].data(), host().chain())) + { + case ImportResult::Success: + _peer->addRating(100); + break; + case ImportResult::FutureTimeKnown: + //TODO: Rating dependent on how far in future it is. + break; + + case ImportResult::Malformed: + case ImportResult::BadChain: + _peer->disable("Malformed block received."); + return; + + case ImportResult::AlreadyInChain: + case ImportResult::AlreadyKnown: + break; + + case ImportResult::FutureTimeUnkwnown: + case ImportResult::UnknownParent: + clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; + resetSyncFor(_peer, h, _r[1].toInt()); + break; + default:; + } + + DEV_GUARDED(_peer->x_knownBlocks) + _peer->m_knownBlocks.insert(h); + } + DEV_INVARIANT_CHECK; +} + PV60Sync::PV60Sync(EthereumHost& _host): BlockChainSync(_host) { + resetSync(); } SyncStatus PV60Sync::status() const @@ -123,13 +317,44 @@ void PV60Sync::setState(EthereumPeer* _peer, SyncState _s, bool _isSyncing, bool changeSyncer(nullptr, _needHelp); assert(!!m_syncer || _s == SyncState::Idle); +} - if (!_isSyncing) - { - m_syncingLatestHash = h256(); - m_syncingTotalDifficulty = 0; - m_syncingNeededBlocks.clear(); - } +void PV60Sync::resetSync() +{ + m_syncingLatestHash = h256(); + m_syncingLastReceivedHash = h256(); + m_syncingTotalDifficulty = 0; + m_syncingNeededBlocks.clear(); +} + +void PV60Sync::restartSync() +{ + resetSync(); + host().bq().clear(); + if (isSyncing()) + transition(m_syncer, SyncState::Idle); +} + +void PV60Sync::completeSync() +{ + if (isSyncing()) + transition(m_syncer, SyncState::Idle); +} + +void PV60Sync::pauseSync() +{ + if (isSyncing()) + setState(m_syncer, SyncState::Waiting, true); +} + +void PV60Sync::continueSync() +{ + transition(m_syncer, SyncState::Blocks); +} + +void PV60Sync::onNewPeer(EthereumPeer* _peer) +{ + setNeedsSyncing(_peer, _peer->m_latestHash, _peer->m_totalDifficulty); } void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _needHelp) @@ -151,7 +376,7 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ m_syncingLatestHash = _peer->m_latestHash; m_syncingTotalDifficulty = _peer->m_totalDifficulty; setState(_peer, _s, true); - _peer->requestHashes(m_syncingLatestHash); + _peer->requestHashes(m_syncingLastReceivedHash ? m_syncingLastReceivedHash : m_syncingLatestHash); DEV_INVARIANT_CHECK; return; } @@ -175,22 +400,23 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; return; } - if (shouldGrabBlocks(_peer)) + if (shouldGrabBlocks()) { clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash << ", was" << host().latestBlockSent() << "]"; downloadMan().resetToChain(m_syncingNeededBlocks); + resetSync(); } else { clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring."; - m_syncingLatestHash = h256(); + resetSync(); setState(_peer, SyncState::Idle, false); return; } assert (isSyncing(_peer)); } // run through into... - if (m_state == SyncState::Idle || m_state == SyncState::Hashes || m_state == SyncState::Blocks) + if (m_state == SyncState::Idle || m_state == SyncState::Hashes || m_state == SyncState::Blocks || m_state == SyncState::Waiting) { // Looks like it's the best yet for total difficulty. Set to download. setState(_peer, SyncState::Blocks, isSyncing(_peer), _needHelp); // will kick off other peers to help if available. @@ -201,7 +427,7 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ } else if (_s == SyncState::NewBlocks) { - if (m_state != SyncState::Idle && m_state != SyncState::NewBlocks) + if (m_state != SyncState::Idle && m_state != SyncState::NewBlocks && m_state != SyncState::Waiting) clog(NetWarn) << "Bad state: Asking new blocks while syncing!"; else { @@ -211,6 +437,16 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ return; } } + else if (_s == SyncState::Waiting) + { + if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks && m_state != SyncState::Hashes && m_state != SyncState::Waiting) + clog(NetWarn) << "Bad state: Entering waiting state while not downloading blocks!"; + else + { + setState(_peer, SyncState::Waiting, isSyncing(_peer), _needHelp); + return; + } + } else if (_s == SyncState::Idle) { host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; }); @@ -240,16 +476,9 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ clog(NetWarn) << "Invalid state transition:" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); } -void PV60Sync::requestBlocks(EthereumPeer* _peer) +void PV60Sync::resetSyncFor(EthereumPeer* _peer, h256 _latestHash, u256 _td) { - _peer->requestBlocks(); - if (_peer->m_asking != Asking::Blocks) //nothing to download - { - noteDoneBlocks(_peer, false); - if (downloadMan().isComplete()) - transition(_peer, SyncState::Idle); - return; - } + setNeedsSyncing(_peer, _latestHash, _td); } void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 _latestHash, u256 _td) @@ -263,16 +492,21 @@ void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 _latestHash, u256 _td) _peer->session()->addNote("sync", string(isSyncing(_peer) ? "ongoing" : "holding") + (needsSyncing(_peer) ? " & needed" : "")); } +bool PV60Sync::needsSyncing(EthereumPeer* _peer) const +{ + return !!_peer->m_latestHash; +} + bool PV60Sync::isSyncing(EthereumPeer* _peer) const { return m_syncer == _peer; } -bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const +bool PV60Sync::shouldGrabBlocks() const { - auto td = _peer->m_totalDifficulty; - auto lh = _peer->m_latestHash; - auto ctd = host().chain().details().totalDifficulty; + auto td = m_syncingTotalDifficulty; + auto lh = m_syncingLatestHash; + auto ctd = host().chain().details().totalDifficulty; if (m_syncingNeededBlocks.empty()) return false; @@ -300,11 +534,12 @@ void PV60Sync::attemptSync(EthereumPeer* _peer) return; } - h256 c = host().chain().currentHash(); unsigned n = host().chain().number(); u256 td = host().chain().details().totalDifficulty; + if (host().bq().isActive()) + td += host().bq().difficulty(); - clog(NetAllDetail) << "Attempt chain-grab? Latest:" << c << ", number:" << n << ", TD:" << td << " versus " << _peer->m_totalDifficulty; + clog(NetAllDetail) << "Attempt chain-grab? Latest:" << (m_syncingLastReceivedHash ? m_syncingLastReceivedHash : m_syncingLatestHash) << ", number:" << n << ", TD:" << td << " versus " << _peer->m_totalDifficulty; if (td >= _peer->m_totalDifficulty) { clog(NetAllDetail) << "No. Our chain is better."; @@ -326,7 +561,7 @@ void PV60Sync::noteNeedsSyncing(EthereumPeer* _peer) { clog(NetAllDetail) << "Sync in progress: Just set to help out."; if (m_state == SyncState::Blocks) - _peer->requestBlocks(); + requestBlocks(_peer); } else // otherwise check to see if we should be downloading... @@ -370,6 +605,11 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp) assert(!!m_syncer || m_state == SyncState::Idle); } +void PV60Sync::peerDoneBlocks(EthereumPeer* _peer) +{ + noteDoneBlocks(_peer, false); +} + void PV60Sync::noteDoneBlocks(EthereumPeer* _peer, bool _clemency) { resetNeedsSyncing(_peer); @@ -399,125 +639,6 @@ void PV60Sync::noteDoneBlocks(EthereumPeer* _peer, bool _clemency) _peer->m_sub.doneFetch(); } -void PV60Sync::onPeerStatus(EthereumPeer* _peer) -{ - RecursiveGuard l(x_sync); - DEV_INVARIANT_CHECK; - if (_peer->m_genesisHash != host().chain().genesisHash()) - _peer->disable("Invalid genesis hash"); - else if (_peer->m_protocolVersion != host().protocolVersion() && _peer->m_protocolVersion != EthereumHost::c_oldProtocolVersion) - _peer->disable("Invalid protocol version."); - else if (_peer->m_networkId != host().networkId()) - _peer->disable("Invalid network identifier."); - else if (_peer->session()->info().clientVersion.find("/v0.7.0/") != string::npos) - _peer->disable("Blacklisted client version."); - else if (host().isBanned(_peer->session()->id())) - _peer->disable("Peer banned for previous bad behaviour."); - else - { - unsigned estimatedHashes = estimateHashes(); - _peer->m_expectedHashes = estimatedHashes; - setNeedsSyncing(_peer, _peer->m_latestHash, _peer->m_totalDifficulty); - } - DEV_INVARIANT_CHECK; -} - -void PV60Sync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) -{ - RecursiveGuard l(x_sync); - DEV_INVARIANT_CHECK; - unsigned itemCount = _r.itemCount(); - clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); - - _peer->setIdle(); - if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks) - clog(NetWarn) << "Unexpected Blocks received!"; - - if (itemCount == 0) - { - // Got to this peer's latest block - just give up. - noteDoneBlocks(_peer, false); - if (downloadMan().isComplete()) - transition(_peer, SyncState::Idle); - return; - } - - unsigned success = 0; - unsigned future = 0; - unsigned unknown = 0; - unsigned got = 0; - unsigned repeated = 0; - u256 maxDifficulty = 0; - h256 maxUnknown; - - for (unsigned i = 0; i < itemCount; ++i) - { - auto h = BlockInfo::headerHash(_r[i].data()); - if (_peer->m_sub.noteBlock(h)) - { - _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) - { - case ImportResult::Success: - success++; - break; - - case ImportResult::Malformed: - case ImportResult::BadChain: - _peer->disable("Malformed block received."); - return; - - case ImportResult::FutureTimeKnown: - future++; - break; - case ImportResult::AlreadyInChain: - case ImportResult::AlreadyKnown: - got++; - break; - - case ImportResult::FutureTimeUnkwnown: - future++; //Fall through - - case ImportResult::UnknownParent: - { - unknown++; - if (m_state == SyncState::NewBlocks) - { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); - if (bi.difficulty > maxDifficulty) - { - maxDifficulty = bi.difficulty; - maxUnknown = h; - } - } - break; - } - - default:; - } - } - else - { - _peer->addRating(0); // -1? - repeated++; - } - } - - clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; - - if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) - { - if (downloadMan().isComplete()) - transition(_peer, SyncState::Idle); - else if (!got) - transition(_peer, m_state); - else - noteDoneBlocks(_peer, false); - } - DEV_INVARIANT_CHECK; -} - void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); @@ -565,9 +686,7 @@ void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) if (m_syncingNeededBlocks.size() > _peer->m_expectedHashes) { _peer->disable("Too many hashes"); - m_syncingNeededBlocks.clear(); - m_syncingLatestHash = h256(); - transition(_peer, SyncState::Idle); + restartSync(); return; } // run through - ask for more. @@ -575,66 +694,6 @@ void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) DEV_INVARIANT_CHECK; } - -void PV60Sync::abortSync(EthereumPeer* _peer) -{ - if (isSyncing(_peer)) - { - host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; }); - transition(_peer, SyncState::Idle, true); - } - DEV_INVARIANT_CHECK; -} - -void PV60Sync::onPeerAborting(EthereumPeer* _peer) -{ - abortSync(_peer); - DEV_INVARIANT_CHECK; -} - -void PV60Sync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) -{ - DEV_INVARIANT_CHECK; - RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); - clog(NetMessageSummary) << "NewBlock: " << h; - - if (_r.itemCount() != 2) - _peer->disable("NewBlock without 2 data fields."); - else - { - switch (host().bq().import(_r[0].data(), host().chain())) - { - case ImportResult::Success: - _peer->addRating(100); - break; - case ImportResult::FutureTimeKnown: - //TODO: Rating dependent on how far in future it is. - break; - - case ImportResult::Malformed: - case ImportResult::BadChain: - _peer->disable("Malformed block received."); - return; - - case ImportResult::AlreadyInChain: - case ImportResult::AlreadyKnown: - break; - - case ImportResult::FutureTimeUnkwnown: - case ImportResult::UnknownParent: - clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; - setNeedsSyncing(_peer, h, _r[1].toInt()); - break; - default:; - } - - DEV_GUARDED(_peer->x_knownBlocks) - _peer->m_knownBlocks.insert(h); - } - DEV_INVARIANT_CHECK; -} - void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); @@ -672,11 +731,28 @@ void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { clog(NetNote) << "Not syncing and new block hash discovered: syncing without help."; downloadMan().resetToChain(m_syncingNeededBlocks); + resetSync(); transition(_peer, SyncState::NewBlocks, false, false); } DEV_INVARIANT_CHECK; } +void PV60Sync::abortSync(EthereumPeer* _peer) +{ + if (isSyncing(_peer)) + { + host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; }); + transition(_peer, SyncState::Idle, true); + } + DEV_INVARIANT_CHECK; +} + +void PV60Sync::onPeerAborting(EthereumPeer* _peer) +{ + abortSync(_peer); + DEV_INVARIANT_CHECK; +} + bool PV60Sync::invariants() const { if (m_state == SyncState::Idle && !!m_syncer) @@ -696,6 +772,8 @@ bool PV60Sync::invariants() const host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Blocks) blocks = true; return !blocks; }); if (!blocks) return false; + if (downloadMan().isComplete()) + return false; } return true; } diff --git a/libethereum/BlockChainSync.h b/libethereum/BlockChainSync.h index 2c3f61de6..1337c5c90 100644 --- a/libethereum/BlockChainSync.h +++ b/libethereum/BlockChainSync.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file EthereumHost.h +/** @file BlockChainSync.h * @author Gav Wood * @date 2014 */ @@ -22,23 +22,14 @@ #pragma once #include -#include -#include -#include -#include -#include -#include #include -#include #include #include #include #include "CommonNet.h" -#include "EthereumPeer.h" //TODO: forward decl #include "DownloadMan.h" - namespace dev { @@ -49,98 +40,174 @@ namespace eth class EthereumHost; class BlockQueue; +class EthereumPeer; /** - * @brief BlockChain synchronization strategy class - * @doWork Syncs to peers and sends new blocks and transactions. + * @brief Base BlockChain synchronization strategy class. + * Syncs to peers and keeps up to date. Base class handles blocks downloading but does not contain any details on state transfer logic. */ class BlockChainSync: public HasInvariants { public: BlockChainSync(EthereumHost& _host); - - /// Will block on network process events. virtual ~BlockChainSync(); - void abortSync(); + void abortSync(); ///< Abort all sync activity DownloadMan const& downloadMan() const; DownloadMan& downloadMan(); + + /// @returns true is Sync is in progress virtual bool isSyncing() const = 0; - virtual void onPeerStatus(EthereumPeer* _peer); ///< Called by peer to report status - virtual void onPeerBlocks(EthereumPeer* _peer, RLP const& _r) = 0; ///< Called by peer once it has new blocks during syn - virtual void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) = 0; ///< Called by peer once it has new blocks - virtual void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; ///< Called by peer once it has new hashes - virtual void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; ///< Called by peer once it has another sequential block of hashes during sync - virtual void onPeerAborting(EthereumPeer* _peer) = 0; ///< Called by peer when it is disconnecting + + /// Called by peer to report status + virtual void onPeerStatus(EthereumPeer* _peer); + + /// Called by peer once it has new blocks during syn + virtual void onPeerBlocks(EthereumPeer* _peer, RLP const& _r); + + /// Called by peer once it has new blocks + virtual void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); + + /// Called by peer once it has new hashes + virtual void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; + + /// Called by peer once it has another sequential block of hashes during sync + virtual void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; + + /// Called by peer when it is disconnecting + virtual void onPeerAborting(EthereumPeer* _peer) = 0; + + /// @returns Synchonization status virtual SyncStatus status() const = 0; static char const* stateName(SyncState _s) { return s_stateNames[static_cast(_s)]; } -private: - static char const* const s_stateNames[static_cast(SyncState::Size)]; +protected: + //To be implemented in derived classes: + /// New valid peer appears + virtual void onNewPeer(EthereumPeer* _peer) = 0; - void setState(SyncState _s); + /// Peer done downloading blocks + virtual void peerDoneBlocks(EthereumPeer* _peer) = 0; - bool invariants() const override = 0; + /// Resume downloading after witing state + virtual void continueSync() = 0; - EthereumHost& m_host; - Handler m_bqRoomAvailable; - HashDownloadMan m_hashMan; + /// Restart sync + virtual void restartSync() = 0; -protected: + /// Called after all blocks have been donloaded + virtual void completeSync() = 0; + + /// Enter waiting state + virtual void pauseSync() = 0; + + /// Restart sync for given peer + virtual void resetSyncFor(EthereumPeer* _peer, h256 _latestHash, u256 _td) = 0; EthereumHost& host() { return m_host; } EthereumHost const& host() const { return m_host; } + + /// Estimates max number of hashes peers can give us. unsigned estimateHashes(); + /// Request blocks from peer if needed + void requestBlocks(EthereumPeer* _peer); + +private: + static char const* const s_stateNames[static_cast(SyncState::Size)]; + bool invariants() const override = 0; + EthereumHost& m_host; + HashDownloadMan m_hashMan; + +protected: + Handler m_bqRoomAvailable; mutable RecursiveMutex x_sync; SyncState m_state = SyncState::Idle; ///< Current sync state SyncState m_lastActiveState = SyncState::Idle; ///< Saved state before entering waiting queue mode unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. }; + +/** + * @brief Syncrhonization over PV60. Selects a single peer and tries to downloading hashes from it. After hash downaload is complete + * Syncs to peers and keeps up to date + */ class PV60Sync: public BlockChainSync { public: - PV60Sync(EthereumHost& _host); + /// @returns true is Sync is in progress bool isSyncing() const override { return !!m_syncer; } - void onPeerStatus(EthereumPeer* _peer) override; ///< Called by peer to report status - void onPeerBlocks(EthereumPeer* _peer, RLP const& _r) override; ///< Called by peer once it has new blocks during syn - void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) override; ///< Called by peer once it has new blocks - void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) override; ///< Called by peer once it has new hashes - void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) override; ///< Called by peer once it has another sequential block of hashes during sync - void onPeerAborting(EthereumPeer* _peer) override; ///< Called by peer when it is disconnecting + + /// Called by peer once it has new hashes + void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) override; + + /// Called by peer once it has another sequential block of hashes during sync + void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) override; + + /// Called by peer when it is disconnecting + void onPeerAborting(EthereumPeer* _peer) override; + + /// @returns Sync status SyncStatus status() const override; + void onNewPeer(EthereumPeer* _peer) override; + void continueSync() override; + void peerDoneBlocks(EthereumPeer* _peer) override; + void restartSync() override; + void completeSync() override; + void pauseSync() override; + void resetSyncFor(EthereumPeer* _peer, h256 _latestHash, u256 _td) override; + +private: + /// Transition sync state in a particular direction. @param _peer Peer that is responsible for state tranfer void transition(EthereumPeer* _peer, SyncState _s, bool _force = false, bool _needHelp = true); + + /// Reset peer syncing requirements state. void resetNeedsSyncing(EthereumPeer* _peer) { setNeedsSyncing(_peer, h256(), 0); } - bool needsSyncing(EthereumPeer* _peer) const { return !!_peer->m_latestHash; } + /// Update peer syncing requirements state. void setNeedsSyncing(EthereumPeer* _peer, h256 _latestHash, u256 _td); - bool shouldGrabBlocks(EthereumPeer* _peer) const; + + /// Do we presently need syncing with this peer? + bool needsSyncing(EthereumPeer* _peer) const; + + /// Check whether the session should bother grabbing blocks. + bool shouldGrabBlocks() const; + + /// Attempt to begin syncing with the peer; first check the peer has a more difficlult chain to download, then start asking for hashes, then move to blocks void attemptSync(EthereumPeer* _peer); + + /// Update our syncing state void setState(EthereumPeer* _peer, SyncState _s, bool _isSyncing = false, bool _needHelp = false); + + /// Check if peer is main syncer bool isSyncing(EthereumPeer* _peer) const; + + /// Check if we need (re-)syncing with the peer. void noteNeedsSyncing(EthereumPeer* _who); + + /// Set main syncing peer void changeSyncer(EthereumPeer* _syncer, bool _needHelp); + + /// Called when peer done downloading blocks void noteDoneBlocks(EthereumPeer* _who, bool _clemency); + + /// Abort syncing for peer void abortSync(EthereumPeer* _peer); - void requestBlocks(EthereumPeer* _peer); + /// Reset hash chain syncing + void resetSync(); -private: bool invariants() const override; - h256s m_knownHashes; ///< List of block hashes we need to download. - h256s m_syncingNeededBlocks; ///< The blocks that we should download from this peer. h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer. h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync. u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync. EthereumPeer* m_syncer = nullptr; // TODO: switch to weak_ptr - }; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c8bbfc119..921e505fd 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -37,7 +37,7 @@ const char* BlockQueueChannel::name() { return EthOrange "[]>"; } const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; } #endif -size_t const c_maxKnownCount = 100000; +size_t const c_maxKnownCount = 10000; size_t const c_maxKnownSize = 128 * 1024 * 1024; size_t const c_maxUnknownCount = 100000; size_t const c_maxUnknownSize = 512 * 1024 * 1024; // Block size can be ~50kb @@ -81,6 +81,8 @@ void BlockQueue::clear() m_unknownCount = 0; m_knownSize = 0; m_knownCount = 0; + m_difficulty = 0; + m_drainingDifficulty = 0; } void BlockQueue::verifierBody() @@ -194,7 +196,6 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { // TODO: quick verify @@ -229,6 +230,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo cblockq << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; + m_difficulty += bi.difficulty; bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnkwnown : ImportResult::FutureTimeKnown; } @@ -249,6 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); + m_difficulty += bi.difficulty; m_unknownCount++; return ImportResult::UnknownParent; @@ -262,6 +265,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); + m_difficulty += bi.difficulty; m_knownCount++; noteReady_WITH_LOCK(h); @@ -351,13 +355,16 @@ bool BlockQueue::doneDrain(h256s const& _bad) WriteGuard l(m_lock); DEV_INVARIANT_CHECK; m_drainingSet.clear(); + m_difficulty -= m_drainingDifficulty; + m_drainingDifficulty = 0; if (_bad.size()) { // at least one of them was bad. m_knownBad += _bad; for (h256 const& b : _bad) updateBad(b); - } return !m_readySet.empty(); + } + return !m_readySet.empty(); } void BlockQueue::tick(BlockChain const& _bc) @@ -434,6 +441,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) if (m_drainingSet.empty()) { bool wasFull = knownFull(); + m_drainingDifficulty = 0; DEV_GUARDED(m_verification) { o_out.resize(min(_max, m_verified.size())); @@ -446,6 +454,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); + m_drainingDifficulty += bs.verified.info.difficulty; m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; @@ -525,3 +534,19 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockQueueStatus const& _ return _out; } + +u256 BlockQueue::difficulty() const +{ + UpgradableGuard l(m_lock); + return m_difficulty; +} + +bool BlockQueue::isActive() const +{ + UpgradableGuard l(m_lock); + if (m_readySet.empty() && m_drainingSet.empty()) + DEV_GUARDED(m_verification) + if (m_verified.empty() && m_verifying.empty() && m_unverified.empty()) + return false; + return true; +} diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index 8f079aa66..106c08534 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -117,6 +117,8 @@ public: bool knownFull() const; bool unknownFull() const; + u256 difficulty() const; // Total difficulty of queueud blocks + bool isActive() const; private: struct UnverifiedBlock @@ -158,6 +160,8 @@ private: std::atomic m_knownSize; ///< Tracks total size in bytes of all known blocks; std::atomic m_unknownCount; ///< Tracks total count of unknown blocks. Used to avoid additional syncing std::atomic m_knownCount; ///< Tracks total count of known blocks. Used to avoid additional syncing + u256 m_difficulty; ///< Total difficulty of blocks in the queue + u256 m_drainingDifficulty; ///< Total difficulty of blocks in draining }; std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s); diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 8b8a7c305..64250ca90 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -289,6 +289,11 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) { + if (_peer->isCriticalSyncing()) + { + clog(NetAllDetail) << "Ignoring transaction from peer we are syncing with"; + return; + } unsigned itemCount = _r.itemCount(); clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)"; Guard l(_peer->x_knownTransactions); diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index aed35c192..7dfba1b0d 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -80,6 +80,7 @@ public: BlockChain const& chain() const { return m_chain; } BlockQueue& bq() { return m_bq; } + BlockQueue const& bq() const { return m_bq; } SyncStatus status() const; h256 latestBlockSent() { return m_latestBlockSent; } static char const* stateName(SyncState _s) { return s_stateNames[static_cast(_s)]; } diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index 2ffbe9101..6993f9b1a 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -141,11 +141,8 @@ private: /// This is built as we ask for hashes. Once no more hashes are given, we present this to the /// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks. - h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer. - h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync. - u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync. unsigned m_expectedHashes = 0; ///< Estimated upper bound of hashes to expect from this peer. - u256 m_syncHashNumber = 0; ///< Number of latest hash we sync to (PV61+) + u256 m_syncHashNumber = 0; ///< Number of latest hash we sync to (PV61+) h256 m_syncHash; ///< Latest hash we sync to (PV60) /// Once we're asking for blocks, this becomes in use. From d0cf2e94c8eb00961eb73d3fa108f3bb4d22d0c2 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Jun 2015 21:59:06 +0200 Subject: [PATCH 066/103] fixed syncing to unknown new block --- libethereum/BlockChainSync.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 64de5f590..c8c81c37f 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -225,8 +225,11 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) } if (m_state == SyncState::NewBlocks && unknown > 0) + { + completeSync(); resetSyncFor(_peer, maxUnknown, std::numeric_limits::max()); //TODO: proper total difficuty - else if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) + } + if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) { if (downloadMan().isComplete()) completeSync(); From 18da764363f88e891466b5db2afac76961462584 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Jun 2015 22:04:20 +0200 Subject: [PATCH 067/103] restored queue limit --- libethereum/BlockQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 921e505fd..4555ecb2b 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -37,7 +37,7 @@ const char* BlockQueueChannel::name() { return EthOrange "[]>"; } const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; } #endif -size_t const c_maxKnownCount = 10000; +size_t const c_maxKnownCount = 100000; size_t const c_maxKnownSize = 128 * 1024 * 1024; size_t const c_maxUnknownCount = 100000; size_t const c_maxUnknownSize = 512 * 1024 * 1024; // Block size can be ~50kb From c0de6de5dba36a35280ee6f133f5049965615d57 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Jun 2015 22:49:57 +0200 Subject: [PATCH 068/103] Fixed nodes format string. --- alethzero/MainWin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 848020cbc..e0d7311c4 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1158,7 +1158,7 @@ void Main::refreshNetwork() auto ns = web3()->nodes(); for (p2p::Peer const& i: ns) - ui->nodes->insertItem(sessions.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") + ui->nodes->insertItem(sessions.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( %4 ) - *%5") .arg(QString::fromStdString(i.id.abridged())) .arg(QString::fromStdString(i.endpoint.address.to_string())) .arg(i.id == web3()->id() ? "self" : sessions.count(i.id) ? sessions[i.id] : "disconnected") From 2fe2b202b8039d18fbb5bdfcc25ca7dbe895243c Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Jun 2015 23:21:07 +0200 Subject: [PATCH 069/103] fixed deadlock on resume --- libethereum/BlockChainSync.cpp | 1 - libethereum/BlockQueue.cpp | 52 ++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index c8c81c37f..bd0b10c7c 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -364,7 +364,6 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ { clog(NetMessageSummary) << "Transition!" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); - //DEV_INVARIANT_CHECK; if (m_state == SyncState::Idle && _s != SyncState::Idle) _peer->m_requireTransactions = true; diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 4555ecb2b..254bf3300 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -37,7 +37,7 @@ const char* BlockQueueChannel::name() { return EthOrange "[]>"; } const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; } #endif -size_t const c_maxKnownCount = 100000; +size_t const c_maxKnownCount = 10000; size_t const c_maxKnownSize = 128 * 1024 * 1024; size_t const c_maxUnknownCount = 100000; size_t const c_maxUnknownSize = 512 * 1024 * 1024; // Block size can be ~50kb @@ -196,6 +196,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; + try { // TODO: quick verify @@ -435,34 +436,35 @@ bool BlockQueue::unknownFull() const void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) { - WriteGuard l(m_lock); - DEV_INVARIANT_CHECK; - - if (m_drainingSet.empty()) + bool wasFull = false; + DEV_WRITE_GUARDED(m_lock) { - bool wasFull = knownFull(); - m_drainingDifficulty = 0; - DEV_GUARDED(m_verification) - { - o_out.resize(min(_max, m_verified.size())); - for (unsigned i = 0; i < o_out.size(); ++i) - swap(o_out[i], m_verified[i]); - m_verified.erase(m_verified.begin(), advanced(m_verified.begin(), o_out.size())); - } - for (auto const& bs: o_out) + DEV_INVARIANT_CHECK; + wasFull = knownFull(); + if (m_drainingSet.empty()) { - // TODO: @optimise use map rather than vector & set. - auto h = bs.verified.info.hash(); - m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; - m_readySet.erase(h); - m_knownSize -= bs.verified.block.size(); - m_knownCount--; + m_drainingDifficulty = 0; + DEV_GUARDED(m_verification) + { + o_out.resize(min(_max, m_verified.size())); + for (unsigned i = 0; i < o_out.size(); ++i) + swap(o_out[i], m_verified[i]); + m_verified.erase(m_verified.begin(), advanced(m_verified.begin(), o_out.size())); + } + for (auto const& bs: o_out) + { + // TODO: @optimise use map rather than vector & set. + auto h = bs.verified.info.hash(); + m_drainingSet.insert(h); + m_drainingDifficulty += bs.verified.info.difficulty; + m_readySet.erase(h); + m_knownSize -= bs.verified.block.size(); + m_knownCount--; + } } - if (wasFull && !knownFull()) - m_onRoomAvailable(); } - + if (wasFull && !knownFull()) + m_onRoomAvailable(); } bool BlockQueue::invariants() const From 4918b7e9dd1f055006806cdb9f284b111d41c31b Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Jun 2015 23:22:49 +0200 Subject: [PATCH 070/103] restore limit --- libethereum/BlockQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 254bf3300..f23c7ba52 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -37,7 +37,7 @@ const char* BlockQueueChannel::name() { return EthOrange "[]>"; } const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; } #endif -size_t const c_maxKnownCount = 10000; +size_t const c_maxKnownCount = 100000; size_t const c_maxKnownSize = 128 * 1024 * 1024; size_t const c_maxUnknownCount = 100000; size_t const c_maxUnknownSize = 512 * 1024 * 1024; // Block size can be ~50kb From 2110876e2e7831d832d55877e7e41e7792954543 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Jun 2015 23:27:42 +0200 Subject: [PATCH 071/103] typo fixed --- libethcore/Common.h | 2 +- libethereum/BlockChainSync.cpp | 4 ++-- libethereum/BlockQueue.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 77ec9fa3b..060860a95 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -101,7 +101,7 @@ enum class ImportResult Success = 0, UnknownParent, FutureTimeKnown, - FutureTimeUnkwnown, + FutureTimeUnknown, AlreadyInChain, AlreadyKnown, Malformed, diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index bd0b10c7c..bcc7f72f3 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -186,7 +186,7 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) got++; break; - case ImportResult::FutureTimeUnkwnown: + case ImportResult::FutureTimeUnknown: future++; //Fall through case ImportResult::UnknownParent: @@ -270,7 +270,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) case ImportResult::AlreadyKnown: break; - case ImportResult::FutureTimeUnkwnown: + case ImportResult::FutureTimeUnknown: case ImportResult::UnknownParent: clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; resetSyncFor(_peer, h, _r[1].toInt()); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f23c7ba52..394549076 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -233,7 +233,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownCount++; m_difficulty += bi.difficulty; bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); - return unknown ? ImportResult::FutureTimeUnkwnown : ImportResult::FutureTimeKnown; + return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { From 4b2dfe48ea422751b517369b4c26a7838fe897d5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 17 Jun 2015 23:32:21 +0200 Subject: [PATCH 072/103] fixed eth build --- eth/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/main.cpp b/eth/main.cpp index 43d865346..e1eec1cac 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -764,7 +764,8 @@ int main(int argc, char** argv) case ImportResult::Success: good++; break; case ImportResult::AlreadyKnown: alreadyHave++; break; case ImportResult::UnknownParent: unknownParent++; break; - case ImportResult::FutureTime: futureTime++; break; + case ImportResult::FutureTimeUnknown: unknownParent++; futureTime++; break; + case ImportResult::FutureTimeKnown: futureTime++; break; default: bad++; break; } } From 4e48ba1d4a1bf801626cac5e7e03672fae05079b Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Thu, 18 Jun 2015 00:44:20 +0200 Subject: [PATCH 073/103] false positive test introduced --- test/libwhisper/bloomFilter.cpp | 58 +++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/libwhisper/bloomFilter.cpp b/test/libwhisper/bloomFilter.cpp index adf76c429..799c4caf6 100644 --- a/test/libwhisper/bloomFilter.cpp +++ b/test/libwhisper/bloomFilter.cpp @@ -55,8 +55,66 @@ void testRemoveExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) BOOST_REQUIRE(!_f.containsBloom(_h)); } +int calculateExpected(TopicBloomFilter const& f, int const n) +{ + int const m = f.size * 8; // number of bits in the bloom + int const k = f.BitsPerBloom; // number of hash functions (e.g. bits set to 1 in every bloom) + + double singleBitSet = 1.0 / m; // probability of any bit being set after inserting a single bit + double singleBitNotSet = (1.0 - singleBitSet); + + double singleNot = 1; // single bit not set after inserting N elements in the bloom filter + for (int i = 0; i < k * n; ++i) + singleNot *= singleBitNotSet; + + double single = 1.0 - singleNot; // probability of a single bit being set after inserting N elements in the bloom filter + + double kBitsSet = 1; // probability of K bits being set after inserting N elements in the bloom filter + for (int i = 0; i < k; ++i) + kBitsSet *= single; + + return static_cast(kBitsSet * 100 + 0.5); // in percents, rounded up +} + +void testFalsePositiveRate(TopicBloomFilter const& f, int const inserted, Topic& x) +{ + int const c_sampleSize = 1000; + int falsePositive = 0; + + for (int i = 0; i < c_sampleSize; ++i) + { + x = sha3(x); + AbridgedTopic a(x); + if (f.containsBloom(a)) + ++falsePositive; + } + + falsePositive /= (c_sampleSize / 100); // in percents + int expected = calculateExpected(f, inserted); + int allowed = expected + (expected / 5); // allow deviations ~20% + + //cnote << "Inserted: " << inserted << ", False Positive Rate: " << falsePositive << ", Expected: " << expected; + BOOST_REQUIRE(falsePositive <= allowed); +} + BOOST_AUTO_TEST_SUITE(bloomFilter) +BOOST_AUTO_TEST_CASE(falsePositiveRate) +{ + VerbosityHolder setTemporaryLevel(10); + cnote << "Testing Bloom Filter False Positive Rate..."; + + TopicBloomFilter f; + Topic x(0xABCDEF); // deterministic pseudorandom value + + for (int i = 1; i < 21; ++i) + { + x = sha3(x); + f.addBloom(AbridgedTopic(x)); + testFalsePositiveRate(f, i, x); + } +} + BOOST_AUTO_TEST_CASE(bloomFilterRandom) { VerbosityHolder setTemporaryLevel(10); From 3169341b656ae561322a51108d45df6a9aecd543 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 18 Jun 2015 08:00:16 +0200 Subject: [PATCH 074/103] add network flag --- test/TestHelper.cpp | 5 ++++- test/TestHelper.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 743b16273..4e1ad92b4 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -754,6 +754,8 @@ Options::Options() checkState = true; else if (arg == "--wallet") wallet = true; + else if (arg == "--network") + network = true; else if (arg == "--all") { performance = true; @@ -761,7 +763,8 @@ Options::Options() memory = true; inputLimits = true; bigData = true; - wallet= true; + wallet = true; + network = true; } else if (arg == "--singletest" && i + 1 < argc) { diff --git a/test/TestHelper.h b/test/TestHelper.h index df33c00d8..ab52a550c 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -223,6 +223,7 @@ public: bool inputLimits = false; bool bigData = false; bool wallet = false; + bool network = false; /// @} /// Get reference to options From 00d8627d3512115a12fe616ee81845854b8c597b Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 18 Jun 2015 08:00:46 +0200 Subject: [PATCH 075/103] make network tests optional --- test/libp2p/peer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/libp2p/peer.cpp b/test/libp2p/peer.cpp index bcb6d4085..5fea9225e 100644 --- a/test/libp2p/peer.cpp +++ b/test/libp2p/peer.cpp @@ -24,6 +24,8 @@ #include #include #include +#include + using namespace std; using namespace dev; using namespace dev::p2p; @@ -38,6 +40,9 @@ BOOST_FIXTURE_TEST_SUITE(p2p, P2PFixture) BOOST_AUTO_TEST_CASE(host) { + if (!test::Options::get().network) + return; + VerbosityHolder sentinel(10); NetworkPreferences host1prefs("127.0.0.1", 30301, false); @@ -64,6 +69,9 @@ BOOST_AUTO_TEST_CASE(host) BOOST_AUTO_TEST_CASE(networkConfig) { + if (!test::Options::get().network) + return; + Host save("Test", NetworkPreferences(false)); bytes store(save.saveNetwork()); @@ -73,6 +81,9 @@ BOOST_AUTO_TEST_CASE(networkConfig) BOOST_AUTO_TEST_CASE(saveNodes) { + if (!test::Options::get().network) + return; + VerbosityHolder reduceVerbosity(2); std::list hosts; From 3302539a11a646912ecbacec8db49450d30d6d1b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Jun 2015 10:05:41 +0200 Subject: [PATCH 076/103] OpenCL: Always try single chunk DAG upload - Removed the `--force-single-chunk` option - Always attempt to create a single chunk DAG buffer in the GPU. If that fails then and only then switch to multiple chunks. This change is motivated by the fact that many GPUs appear to be able to actually allocate a lot more than what CL_DEVICE_MAX_MEM_ALLOC_SIZE returns which proves that the results of querying the CL API on this basically can't be trusted. --- ethminer/MinerAux.h | 11 ++---- libethash-cl/ethash_cl_miner.cpp | 61 ++++++++++++++------------------ libethash-cl/ethash_cl_miner.h | 3 -- libethcore/Ethash.cpp | 3 +- libethcore/Ethash.h | 3 +- 5 files changed, 31 insertions(+), 50 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 3351b90de..a609754dd 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -134,8 +134,6 @@ public: m_clAllowCPU = true; else if (arg == "--cl-extragpu-mem" && i + 1 < argc) m_extraGPUMemory = 1000000 * stol(argv[++i]); - else if (arg == "--force-single-chunk") - m_forceSingleChunk = true; else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; @@ -273,7 +271,6 @@ public: m_openclDevice, m_clAllowCPU, m_extraGPUMemory, - m_forceSingleChunk, m_currentBlock )) { @@ -318,10 +315,9 @@ public: << " --opencl-device When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << " -t, --mining-threads Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl << " --allow-opencl-cpu Allows CPU to be considered as an OpenCL device if the OpenCL platform supports it." << endl - << " --list-devices List the detected OpenCL devices and exit." < m_currentBlock; // default value is 350MB of GPU memory for other stuff (windows system rendering, e.t.c.) unsigned m_extraGPUMemory = 350000000; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index b160cdd94..2fc6102fb 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -140,12 +140,10 @@ unsigned ethash_cl_miner::getNumDevices(unsigned _platformId) bool ethash_cl_miner::configureGPU( bool _allowCPU, unsigned _extraGPUMemory, - bool _forceSingleChunk, boost::optional _currentBlock ) { s_allowCPU = _allowCPU; - s_forceSingleChunk = _forceSingleChunk; s_extraRequiredGPUMem = _extraGPUMemory; // by default let's only consider the DAG of the first epoch uint64_t dagSize = _currentBlock ? ethash_get_datasize(*_currentBlock) : 1073739904U; @@ -174,7 +172,6 @@ bool ethash_cl_miner::configureGPU( } bool ethash_cl_miner::s_allowCPU = false; -bool ethash_cl_miner::s_forceSingleChunk = false; unsigned ethash_cl_miner::s_extraRequiredGPUMem; bool ethash_cl_miner::searchForAllDevices(function _callback) @@ -288,23 +285,6 @@ bool ethash_cl_miner::init( string device_version = device.getInfo(); ETHCL_LOG("Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")"); - // configure chunk number depending on max allocateable memory - cl_ulong result; - device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result); - if (s_forceSingleChunk || result >= _dagSize) - { - m_dagChunksNum = 1; - ETHCL_LOG( - ((result <= _dagSize && s_forceSingleChunk) ? "Forcing single chunk. Good luck!\n" : "") << - "Using 1 big chunk. Max OpenCL allocateable memory is " << result - ); - } - else - { - m_dagChunksNum = 4; - ETHCL_LOG("Using 4 chunks. Max OpenCL allocateable memory is " << result); - } - if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) { ETHCL_LOG("OpenCL 1.0 is not supported."); @@ -346,26 +326,23 @@ bool ethash_cl_miner::init( ETHCL_LOG(program.getBuildInfo(device).c_str()); return false; } - if (m_dagChunksNum == 1) - { - ETHCL_LOG("Loading single big chunk kernels"); - m_hash_kernel = cl::Kernel(program, "ethash_hash"); - m_search_kernel = cl::Kernel(program, "ethash_search"); - } - else - { - ETHCL_LOG("Loading chunk kernels"); - m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks"); - m_search_kernel = cl::Kernel(program, "ethash_search_chunks"); - } // create buffer for dag - if (m_dagChunksNum == 1) + try { - ETHCL_LOG("Creating one big buffer"); + m_dagChunksNum = 1; m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); + ETHCL_LOG("Created one big buffer for the DAG"); } - else + catch (...) + { + cl_ulong result; + device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result); + ETHCL_LOG( + "Failed to allocate 1 big chunk. Max allocateable memory is " + << result << ". Trying to allocate 4 chunks." + ); + m_dagChunksNum = 4; for (unsigned i = 0; i < m_dagChunksNum; i++) { // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation @@ -376,6 +353,20 @@ bool ethash_cl_miner::init( (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7 )); } + } + + if (m_dagChunksNum == 1) + { + ETHCL_LOG("Loading single big chunk kernels"); + m_hash_kernel = cl::Kernel(program, "ethash_hash"); + m_search_kernel = cl::Kernel(program, "ethash_search"); + } + else + { + ETHCL_LOG("Loading chunk kernels"); + m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks"); + m_search_kernel = cl::Kernel(program, "ethash_search_chunks"); + } // create buffer for header ETHCL_LOG("Creating buffer for header."); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index cc01b0057..f36082a5a 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -44,7 +44,6 @@ public: static bool configureGPU( bool _allowCPU, unsigned _extraGPUMemory, - bool _forceSingleChunk, boost::optional _currentBlock ); @@ -79,8 +78,6 @@ private: unsigned m_workgroup_size; bool m_opencl_1_1; - /// Force dag upload to GPU in a single chunk even if OpenCL thinks you can't do it. Use at your own risk. - static bool s_forceSingleChunk; /// Allow CPU to appear as an OpenCL device or not. Default is false static bool s_allowCPU; /// GPU memory required for other things, like window rendering e.t.c. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index ebf8c5615..b277e3c1c 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -389,13 +389,12 @@ bool Ethash::GPUMiner::configureGPU( unsigned _deviceId, bool _allowCPU, unsigned _extraGPUMemory, - bool _forceSingleChunk, boost::optional _currentBlock ) { s_platformId = _platformId; s_deviceId = _deviceId; - return ethash_cl_miner::configureGPU(_allowCPU, _extraGPUMemory, _forceSingleChunk, _currentBlock); + return ethash_cl_miner::configureGPU(_allowCPU, _extraGPUMemory, _currentBlock); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index a5a7856f1..11e012df5 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -88,7 +88,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); static void listDevices() {} - static bool configureGPU(unsigned, unsigned, bool, unsigned, bool, boost::optional) { return false; } + static bool configureGPU(unsigned, unsigned, bool, unsigned, boost::optional) { return false; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: void kickOff() override @@ -122,7 +122,6 @@ public: unsigned _deviceId, bool _allowCPU, unsigned _extraGPUMemory, - bool _forceSingleChunk, boost::optional _currentBlock ); static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } From 25d2fa1607a1bf8508ce3458bde7995366683805 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Jun 2015 10:38:27 +0200 Subject: [PATCH 077/103] single chunk test: catch only cl::Error --- libethash-cl/ethash_cl_miner.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 2fc6102fb..c5f77045b 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -334,8 +334,11 @@ bool ethash_cl_miner::init( m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); ETHCL_LOG("Created one big buffer for the DAG"); } - catch (...) + catch (cl::Error err) { + int errCode = err.err(); + if (errCode != CL_INVALID_BUFFER_SIZE || errCode != CL_MEM_OBJECT_ALLOCATION_FAILURE) + ETHCL_LOG("Allocating single buffer failed with: " << err.what() << "(" << errCode << ")"); cl_ulong result; device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result); ETHCL_LOG( From 8e5e2f4a9e177c05e11f288993e085a8213d1dd4 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 18 Jun 2015 10:56:47 +0200 Subject: [PATCH 078/103] Catch OpenCL exceptions by const& --- libethash-cl/ethash_cl_miner.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index c5f77045b..315f29685 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -321,7 +321,7 @@ bool ethash_cl_miner::init( ETHCL_LOG("Printing program log"); ETHCL_LOG(program.getBuildInfo(device).c_str()); } - catch (cl::Error err) + catch (cl::Error const& err) { ETHCL_LOG(program.getBuildInfo(device).c_str()); return false; @@ -334,7 +334,7 @@ bool ethash_cl_miner::init( m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); ETHCL_LOG("Created one big buffer for the DAG"); } - catch (cl::Error err) + catch (cl::Error const& err) { int errCode = err.err(); if (errCode != CL_INVALID_BUFFER_SIZE || errCode != CL_MEM_OBJECT_ALLOCATION_FAILURE) @@ -345,6 +345,7 @@ bool ethash_cl_miner::init( "Failed to allocate 1 big chunk. Max allocateable memory is " << result << ". Trying to allocate 4 chunks." ); + // The OpenCL kernel has a hard coded number of 4 chunks at the moment m_dagChunksNum = 4; for (unsigned i = 0; i < m_dagChunksNum; i++) { @@ -404,7 +405,7 @@ bool ethash_cl_miner::init( m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); } } - catch (cl::Error err) + catch (cl::Error const& err) { ETHCL_LOG(err.what() << "(" << err.err() << ")"); return false; @@ -498,7 +499,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook pre_return_event.wait(); #endif } - catch (cl::Error err) + catch (cl::Error const& err) { ETHCL_LOG(err.what() << "(" << err.err() << ")"); } From 212ac9366d9de7c7c92e001aede72db93111b411 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 10 Jun 2015 15:17:42 +0200 Subject: [PATCH 079/103] Cleanup of SecretStore. Added documentation, more failure checking and some general cleanup. --- libdevcore/CommonIO.cpp | 6 +- libdevcore/CommonIO.h | 7 +- libdevcrypto/Common.cpp | 26 +++++- libdevcrypto/SecretStore.cpp | 140 ++++++++++++++++-------------- libdevcrypto/SecretStore.h | 49 +++++++++-- test/libdevcrypto/SecretStore.cpp | 2 +- 6 files changed, 152 insertions(+), 78 deletions(-) diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index 03b22bfc5..e788e7460 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -95,9 +95,11 @@ string dev::contentsString(string const& _file) return contentsGeneric(_file); } -void dev::writeFile(std::string const& _file, bytesConstRef _data) +bool dev::writeFile(std::string const& _file, bytesConstRef _data) { - ofstream(_file, ios::trunc|ios::binary).write((char const*)_data.data(), _data.size()); + ofstream s(_file, ios::trunc | ios::binary); + s.write(reinterpret_cast(_data.data()), _data.size()); + return !!s; } std::string dev::getPassword(std::string const& _prompt) diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h index c8aa830ff..7b1a50be2 100644 --- a/libdevcore/CommonIO.h +++ b/libdevcore/CommonIO.h @@ -56,10 +56,11 @@ std::string contentsString(std::string const& _file); bytesRef contentsNew(std::string const& _file, bytesRef _dest = bytesRef()); /// Write the given binary data into the given file, replacing the file if it pre-exists. -void writeFile(std::string const& _file, bytesConstRef _data); +/// @returns true if writing succeeded. +bool writeFile(std::string const& _file, bytesConstRef _data); /// Write the given binary data into the given file, replacing the file if it pre-exists. -inline void writeFile(std::string const& _file, bytes const& _data) { writeFile(_file, bytesConstRef(&_data)); } -inline void writeFile(std::string const& _file, std::string const& _data) { writeFile(_file, bytesConstRef(_data)); } +inline bool writeFile(std::string const& _file, bytes const& _data) { return writeFile(_file, bytesConstRef(&_data)); } +inline bool writeFile(std::string const& _file, std::string const& _data) { return writeFile(_file, bytesConstRef(_data)); } /// Nicely renders the given bytes to a string, optionally as HTML. /// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line. diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 4ebd6a04b..620ae1b7a 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -178,15 +178,35 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash) bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen) { bytes ret(_dkLen); - PKCS5_PBKDF2_HMAC pbkdf; - pbkdf.DeriveKey(ret.data(), ret.size(), 0, (byte*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _iterations); + if (PKCS5_PBKDF2_HMAC().DeriveKey( + ret.data(), + ret.size(), + 0, + reinterpret_cast(_pass.data()), + _pass.size(), + _salt.data(), + _salt.size(), + _iterations + ) != _iterations) + return bytes(); return ret; } bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen) { bytes ret(_dkLen); - libscrypt_scrypt((uint8_t const*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _n, _r, _p, ret.data(), ret.size()); + if (libscrypt_scrypt( + reinterpret_cast(_pass.data()), + _pass.size(), + _salt.data(), + _salt.size(), + _n, + _r, + _p, + ret.data(), + ret.size() + ) != 0) + return bytes(); return ret; } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index b9d4ccfc6..c1bbf0141 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -36,7 +36,8 @@ namespace fs = boost::filesystem; static const int c_keyFileVersion = 3; -static js::mValue upgraded(std::string const& _s) +/// Upgrade the json-format to the current version. +static js::mValue upgraded(string const& _s) { js::mValue v; js::read_string(_s, v); @@ -84,36 +85,38 @@ static js::mValue upgraded(std::string const& _s) return js::mValue(); } -SecretStore::SecretStore(std::string const& _path): m_path(_path) +SecretStore::SecretStore(string const& _path): m_path(_path) { load(); } -SecretStore::~SecretStore() +bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const { -} - -bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const -{ - (void)_pass; auto rit = m_cached.find(_uuid); if (_useCache && rit != m_cached.end()) return rit->second; auto it = m_keys.find(_uuid); - if (it == m_keys.end()) - return bytes(); - bytes key = decrypt(it->second.first, _pass()); - if (!key.empty()) - m_cached[_uuid] = key; + bytes key; + if (it != m_keys.end()) + { + key = decrypt(it->second.encryptedKey, _pass()); + if (!key.empty()) + m_cached[_uuid] = key; + } return key; } -h128 SecretStore::importSecret(bytes const& _s, std::string const& _pass) +h128 SecretStore::importSecret(bytes const& _s, string const& _pass) { - h128 r = h128::random(); - m_cached[r] = _s; - m_keys[r] = make_pair(encrypt(_s, _pass), std::string()); - save(); + h128 r; + EncryptedKey key{encrypt(_s, _pass), string()}; + if (!key.encryptedKey.empty()) + { + r = h128::random(); + m_cached[r] = _s; + m_keys[r] = move(key); + save(); + } return r; } @@ -122,7 +125,7 @@ void SecretStore::kill(h128 const& _uuid) m_cached.erase(_uuid); if (m_keys.count(_uuid)) { - boost::filesystem::remove(m_keys[_uuid].second); + fs::remove(m_keys[_uuid].filename); m_keys.erase(_uuid); } } @@ -132,50 +135,52 @@ void SecretStore::clearCache() const m_cached.clear(); } -void SecretStore::save(std::string const& _keysPath) +void SecretStore::save(string const& _keysPath) { fs::path p(_keysPath); - boost::filesystem::create_directories(p); + fs::create_directories(p); for (auto& k: m_keys) { - std::string uuid = toUUID(k.first); - std::string filename = (p / uuid).string() + ".json"; + string uuid = toUUID(k.first); + string filename = (p / uuid).string() + ".json"; js::mObject v; js::mValue crypto; - js::read_string(k.second.first, crypto); + js::read_string(k.second.encryptedKey, crypto); v["crypto"] = crypto; v["id"] = uuid; v["version"] = c_keyFileVersion; - writeFile(filename, js::write_string(js::mValue(v), true)); - if (!k.second.second.empty() && k.second.second != filename) - boost::filesystem::remove(k.second.second); - k.second.second = filename; + if (writeFile(filename, js::write_string(js::mValue(v), true))) + { + swap(k.second.filename, filename); + if (!filename.empty() && !fs::equivalent(filename, k.second.filename)) + fs::remove(filename); + } } } -void SecretStore::load(std::string const& _keysPath) +void SecretStore::load(string const& _keysPath) { fs::path p(_keysPath); - boost::filesystem::create_directories(p); + fs::create_directories(p); for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it) - if (is_regular_file(it->path())) + if (fs::is_regular_file(it->path())) readKey(it->path().string(), true); } -h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) +h128 SecretStore::readKey(string const& _file, bool _takeFileOwnership) { cnote << "Reading" << _file; - return readKeyContent(contentsString(_file), _deleteFile ? _file : string()); + return readKeyContent(contentsString(_file), _takeFileOwnership ? _file : string()); } -h128 SecretStore::readKeyContent(std::string const& _content, std::string const& _file) +h128 SecretStore::readKeyContent(string const& _content, string const& _file) { js::mValue u = upgraded(_content); if (u.type() == js::obj_type) { js::mObject& o = u.get_obj(); auto uuid = fromUUID(o["id"].get_str()); - m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _file); + m_keys[uuid] = EncryptedKey{js::write_string(o["crypto"], false), _file}; return uuid; } else @@ -183,62 +188,66 @@ h128 SecretStore::readKeyContent(std::string const& _content, std::string const& return h128(); } -bool SecretStore::recode(h128 const& _uuid, string const& _newPass, std::function const& _pass, KDF _kdf) +bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function const& _pass, KDF _kdf) { -// cdebug << "recode:" << toUUID(_uuid); bytes s = secret(_uuid, _pass, true); if (s.empty()) return false; - m_keys[_uuid].first = encrypt(s, _newPass, _kdf); + m_cached.erase(_uuid); + m_keys[_uuid].encryptedKey = encrypt(s, _newPass, _kdf); save(); return true; } -std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF _kdf) +static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret) { - js::mObject ret; - - // KDF info unsigned dklen = 32; + unsigned iterations = 1 << 19; bytes salt = h256::random().asBytes(); - bytes derivedKey; if (_kdf == KDF::Scrypt) { - unsigned iterations = 262144; unsigned p = 1; unsigned r = 8; - ret["kdf"] = "scrypt"; + o_ret["kdf"] = "scrypt"; { js::mObject params; - params["n"] = (int64_t)iterations; - params["r"] = (int)r; - params["p"] = (int)p; - params["dklen"] = (int)dklen; + params["n"] = int64_t(iterations); + params["r"] = int(r); + params["p"] = int(p); + params["dklen"] = int(dklen); params["salt"] = toHex(salt); - ret["kdfparams"] = params; + o_ret["kdfparams"] = params; } - derivedKey = scrypt(_pass, salt, iterations, r, p, dklen); + return scrypt(_pass, salt, iterations, r, p, dklen); } else { - unsigned iterations = 262144; - ret["kdf"] = "pbkdf2"; + o_ret["kdf"] = "pbkdf2"; { js::mObject params; params["prf"] = "hmac-sha256"; - params["c"] = (int)iterations; + params["c"] = int(iterations); params["salt"] = toHex(salt); - params["dklen"] = (int)dklen; - ret["kdfparams"] = params; + params["dklen"] = int(dklen); + o_ret["kdfparams"] = params; } - derivedKey = pbkdf2(_pass, salt, iterations, dklen); + return pbkdf2(_pass, salt, iterations, dklen); + } +} + +string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) +{ + js::mObject ret; + + bytes derivedKey = deriveNewKey(_pass, _kdf, ret); + if (derivedKey.empty()) + { + cwarn << "Key derivation failed."; + return string(); } -// cdebug << "derivedKey" << toHex(derivedKey); - // cipher info ret["cipher"] = "aes-128-ctr"; h128 key(derivedKey, h128::AlignLeft); -// cdebug << "cipherKey" << key.hex(); h128 iv = h128::random(); { js::mObject params; @@ -248,18 +257,21 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF // cipher text bytes cipherText = encryptSymNoAuth(key, iv, &_v); + if (cipherText.empty()) + { + cwarn << "Key encryption failed."; + return string(); + } ret["ciphertext"] = toHex(cipherText); // and mac. h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); -// cdebug << "macBody" << toHex(ref(derivedKey).cropped(16, 16).toBytes() + cipherText); -// cdebug << "mac" << mac.hex(); ret["mac"] = toHex(mac.ref()); - return js::write_string((js::mValue)ret, true); + return js::write_string(js::mValue(ret), true); } -bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass) +bytes SecretStore::decrypt(string const& _v, string const& _pass) { js::mObject o; { diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 4474212b1..020640e65 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -35,41 +35,80 @@ enum class KDF { Scrypt, }; +/** + * Manages encrypted keys stored in a certain directory on disk. The keys are read into memory + * and changes to the keys are automatically synced to the directory. + * Each file stores exactly one key in a specific JSON format whose file name is derived from the + * UUID of the key. + * @note that most of the functions here affect the filesystem and throw exceptions on failure. + */ class SecretStore { public: + /// Construct a new SecretStore and read all keys in the given directory. SecretStore(std::string const& _path = defaultPath()); - ~SecretStore(); + /// @returns the secret key stored by the given @a _uuid. + /// @param _pass function that returns the password for the key. + /// @param _useCache if true, allow previously decrypted keys to be returned directly. bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const; + /// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory. h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; } + /// Imports the (encrypted) key contained in the json formatted @a _content and stores it in + /// the managed directory. h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; } + /// Imports the decrypted key given by @a _s and stores it, encrypted with + /// (a key derived from) the password @a _pass. h128 importSecret(bytes const& _s, std::string const& _pass); + /// Decrypts and re-encrypts the key identified by @a _uuid. bool recode(h128 const& _uuid, std::string const& _newPass, std::function const& _pass, KDF _kdf = KDF::Scrypt); + /// Removes the key specified by @a _uuid from both memory and disk. void kill(h128 const& _uuid); + /// Returns the uuids of all stored keys. std::vector keys() const { return keysOf(m_keys); } - // Clear any cached keys. + /// Clears all cached decrypted keys. The passwords have to be supplied in order to retrieve + /// secrets again after calling this function. void clearCache() const; - // Doesn't save(). - h128 readKey(std::string const& _file, bool _deleteFile); + /// Import the key from the file @a _file, but do not copy it to the managed directory yet. + /// @param _takeFileOwnership if true, deletes the file if it is not the canonical file for the + /// key (derived from its uuid). + h128 readKey(std::string const& _file, bool _takeFileOwnership); + /// Import the key contained in the json-encoded @a _content, but do not store it in the + /// managed directory. + /// @param _file if given, assume this file contains @a _content and delete it later, if it is + /// not the canonical file for the key (derived from the uuid). h128 readKeyContent(std::string const& _content, std::string const& _file = std::string()); + /// Store all keys in the directory @a _keysPath. void save(std::string const& _keysPath); + /// Store all keys in the managed directory. void save() { save(m_path); } + /// @returns the default path for the managed directory. static std::string defaultPath() { return getDataDir("web3") + "/keys"; } private: + struct EncryptedKey + { + std::string encryptedKey; + std::string filename; + }; + + /// Loads all keys in the given directory. void load(std::string const& _keysPath); void load() { load(m_path); } + /// Encrypts @a _v with a key derived from @a _pass or the empty string on error. static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt); + /// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error. static bytes decrypt(std::string const& _v, std::string const& _pass); + /// Stores decrypted keys by uuid. mutable std::unordered_map m_cached; - std::unordered_map> m_keys; + /// Stores encrypted keys together with the file they were loaded from by uuid. + std::unordered_map m_keys; std::string m_path; }; diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp index 43c201edc..80d850a7c 100644 --- a/test/libdevcrypto/SecretStore.cpp +++ b/test/libdevcrypto/SecretStore.cpp @@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(basic_tests) { cnote << i.first; js::mObject& o = i.second.get_obj(); - SecretStore store("."); + SecretStore store(""); h128 u = store.readKeyContent(js::write_string(o["json"], false)); cdebug << "read uuid" << u; bytes s = store.secret(u, [&](){ return o["password"].get_str(); }); From 58e76408505f7fe901f41d30359a0b169cc9c92d Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 11 Jun 2015 15:01:33 +0200 Subject: [PATCH 080/103] Throw some more exceptions. --- libdevcore/CommonIO.cpp | 5 +++-- libdevcore/CommonIO.h | 8 ++++---- libdevcrypto/Common.cpp | 5 +++-- libdevcrypto/Exceptions.h | 35 +++++++++++++++++++++++++++++++++++ libdevcrypto/SecretStore.cpp | 10 ++++------ libdevcrypto/SecretStore.h | 3 ++- 6 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 libdevcrypto/Exceptions.h diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index e788e7460..d0a1b8c5b 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -95,11 +95,12 @@ string dev::contentsString(string const& _file) return contentsGeneric(_file); } -bool dev::writeFile(std::string const& _file, bytesConstRef _data) +void dev::writeFile(std::string const& _file, bytesConstRef _data) { ofstream s(_file, ios::trunc | ios::binary); s.write(reinterpret_cast(_data.data()), _data.size()); - return !!s; + if (!s) + BOOST_THROW_EXCEPTION(FileError()); } std::string dev::getPassword(std::string const& _prompt) diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h index 7b1a50be2..cc2ef7484 100644 --- a/libdevcore/CommonIO.h +++ b/libdevcore/CommonIO.h @@ -56,11 +56,11 @@ std::string contentsString(std::string const& _file); bytesRef contentsNew(std::string const& _file, bytesRef _dest = bytesRef()); /// Write the given binary data into the given file, replacing the file if it pre-exists. -/// @returns true if writing succeeded. -bool writeFile(std::string const& _file, bytesConstRef _data); +/// Throws exception on error. +void writeFile(std::string const& _file, bytesConstRef _data); /// Write the given binary data into the given file, replacing the file if it pre-exists. -inline bool writeFile(std::string const& _file, bytes const& _data) { return writeFile(_file, bytesConstRef(&_data)); } -inline bool writeFile(std::string const& _file, std::string const& _data) { return writeFile(_file, bytesConstRef(_data)); } +inline void writeFile(std::string const& _file, bytes const& _data) { writeFile(_file, bytesConstRef(&_data)); } +inline void writeFile(std::string const& _file, std::string const& _data) { writeFile(_file, bytesConstRef(_data)); } /// Nicely renders the given bytes to a string, optionally as HTML. /// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line. diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 620ae1b7a..6c66a95d6 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -31,6 +31,7 @@ #include #include "AES.h" #include "CryptoPP.h" +#include "Exceptions.h" using namespace std; using namespace dev; using namespace dev::crypto; @@ -188,7 +189,7 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, _salt.size(), _iterations ) != _iterations) - return bytes(); + BOOST_THROW_EXCEPTION(CryptoException()); return ret; } @@ -206,7 +207,7 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin ret.data(), ret.size() ) != 0) - return bytes(); + BOOST_THROW_EXCEPTION(CryptoException()); return ret; } diff --git a/libdevcrypto/Exceptions.h b/libdevcrypto/Exceptions.h new file mode 100644 index 000000000..675213d8b --- /dev/null +++ b/libdevcrypto/Exceptions.h @@ -0,0 +1,35 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Exceptions.h + * @author Christian + * @date 2016 + */ + +#pragma once + +#include + +namespace dev +{ +namespace crypto +{ + +/// Rare malfunction of cryptographic functions. +DEV_SIMPLE_EXCEPTION_RLP(CryptoException); + +} +} diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index c1bbf0141..14bcae908 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -149,12 +149,10 @@ void SecretStore::save(string const& _keysPath) v["crypto"] = crypto; v["id"] = uuid; v["version"] = c_keyFileVersion; - if (writeFile(filename, js::write_string(js::mValue(v), true))) - { - swap(k.second.filename, filename); - if (!filename.empty() && !fs::equivalent(filename, k.second.filename)) - fs::remove(filename); - } + writeFile(filename, js::write_string(js::mValue(v), true)); + swap(k.second.filename, filename); + if (!filename.empty() && !fs::equivalent(filename, k.second.filename)) + fs::remove(filename); } } diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h index 020640e65..029630b4e 100644 --- a/libdevcrypto/SecretStore.h +++ b/libdevcrypto/SecretStore.h @@ -40,7 +40,8 @@ enum class KDF { * and changes to the keys are automatically synced to the directory. * Each file stores exactly one key in a specific JSON format whose file name is derived from the * UUID of the key. - * @note that most of the functions here affect the filesystem and throw exceptions on failure. + * @note that most of the functions here affect the filesystem and throw exceptions on failure, + * and they also throw exceptions upon rare malfunction in the cryptographic functions. */ class SecretStore { From 8793244ed3aa2f17d61ece83592a406617ff7783 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 11 Jun 2015 19:25:48 +0200 Subject: [PATCH 081/103] Throw exception upon failed encryption. --- libdevcrypto/SecretStore.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 14bcae908..e7409ca15 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -29,6 +29,7 @@ #include #include #include +#include using namespace std; using namespace dev; namespace js = json_spirit; @@ -111,12 +112,11 @@ h128 SecretStore::importSecret(bytes const& _s, string const& _pass) h128 r; EncryptedKey key{encrypt(_s, _pass), string()}; if (!key.encryptedKey.empty()) - { - r = h128::random(); - m_cached[r] = _s; - m_keys[r] = move(key); - save(); - } + BOOST_THROW_EXCEPTION(crypto::CryptoException()); + r = h128::random(); + m_cached[r] = _s; + m_keys[r] = move(key); + save(); return r; } From db88799cf93093fd3e62fb7e9725262d6f23bb55 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 12 Jun 2015 07:35:48 +0200 Subject: [PATCH 082/103] Try not to write files in tests. --- libdevcrypto/SecretStore.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index e7409ca15..86e378589 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -88,7 +88,8 @@ static js::mValue upgraded(string const& _s) SecretStore::SecretStore(string const& _path): m_path(_path) { - load(); + if (!m_path.empty()) + load(); } bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const @@ -137,6 +138,9 @@ void SecretStore::clearCache() const void SecretStore::save(string const& _keysPath) { + if (_keysPath.empty()) + return; + fs::path p(_keysPath); fs::create_directories(p); for (auto& k: m_keys) From 9e51db8b823b1c183af5b979725eef4c3fb071b8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 12 Jun 2015 12:27:32 +0200 Subject: [PATCH 083/103] Do not fail if seed cannot be written to file. --- libdevcrypto/Common.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 6c66a95d6..8567ac12b 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -280,12 +280,12 @@ h256 Nonce::get(bool _commit) BOOST_THROW_EXCEPTION(InvalidState()); // prevent seed reuse if process terminates abnormally - writeFile(s_seedFile, bytes()); + try { writeFile(s_seedFile, bytes()); } catch (FileError const&) {} } h256 prev(s_seed); sha3(prev.ref(), s_seed.ref()); if (_commit) - writeFile(s_seedFile, s_seed.asBytes()); + try { writeFile(s_seedFile, s_seed.asBytes()); } catch (FileError const&) {} return std::move(s_seed); } From 0b6a09b9cfd3898481d5c905944efc3e9bf18274 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 16 Jun 2015 14:00:24 +0200 Subject: [PATCH 084/103] Nonce refactoring. --- libdevcrypto/Common.cpp | 89 ++++++++++++++++++++++++++------------- libdevcrypto/Common.h | 21 ++++++++- libdevcrypto/Exceptions.h | 2 +- 3 files changed, 79 insertions(+), 33 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 8567ac12b..94f78b1e2 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -254,42 +254,71 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash) return s; } -h256 Nonce::get(bool _commit) +mutex Nonce::s_x; + +h256 Nonce::get() { // todo: atomic efface bit, periodic save, kdf, rr, rng // todo: encrypt - static h256 s_seed; - static string s_seedFile(getDataDir() + "/seed"); - static mutex s_x; - Guard l(s_x); - if (!s_seed) + Guard l(Nonce::s_x); + return Nonce::singleton().next(); +} + +// get: Called for the first time: read seed hash from file (or generate) +// before destruction: increment current value and store + +Nonce::~Nonce() +{ + Guard l(Nonce::s_x); + // These might throw. + next(); + commit(); +} + +Nonce& Nonce::singleton() +{ + static Nonce s; + return s; +} + +void Nonce::initialiseIfNeeded() +{ + if (m_value) + return; + + bytes b = contents(seedFile()); + if (b.size() == 32) + memcpy(m_value.data(), b.data(), 32); + else { - static Nonce s_nonce; - bytes b = contents(s_seedFile); - if (b.size() == 32) - memcpy(s_seed.data(), b.data(), 32); - else - { - // todo: replace w/entropy from user and system - std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count()); - std::uniform_int_distribution d(0, 255); - for (unsigned i = 0; i < 32; ++i) - s_seed[i] = (byte)d(s_eng); - } - if (!s_seed) - BOOST_THROW_EXCEPTION(InvalidState()); - - // prevent seed reuse if process terminates abnormally - try { writeFile(s_seedFile, bytes()); } catch (FileError const&) {} + // todo: replace w/entropy from user and system + std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count()); + std::uniform_int_distribution d(0, 255); + for (unsigned i = 0; i < 32; ++i) + m_value[i] = byte(d(s_eng)); } - h256 prev(s_seed); - sha3(prev.ref(), s_seed.ref()); - if (_commit) - try { writeFile(s_seedFile, s_seed.asBytes()); } catch (FileError const&) {} - return std::move(s_seed); + if (!m_value) + BOOST_THROW_EXCEPTION(InvalidState()); + + // prevent seed reuse if process terminates abnormally + // this might throw + writeFile(seedFile(), bytes()); } -Nonce::~Nonce() +h256 Nonce::next() +{ + initialiseIfNeeded(); + m_value = sha3(m_value); + return m_value; +} + +void Nonce::commit() +{ + // this might throw + writeFile(seedFile(), m_value.asBytes()); +} + +string Nonce::seedFile() { - Nonce::get(true); + return getDataDir() + "/seed"; } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7bb51e563..96f525e49 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -24,6 +24,7 @@ #pragma once +#include #include #include #include @@ -180,14 +181,30 @@ struct InvalidState: public dev::Exception {}; h256 kdf(Secret const& _priv, h256 const& _hash); /** - * @brief Generator for nonce material + * @brief Generator for nonce material. */ struct Nonce { - static h256 get(bool _commit = false); + static h256 get(); private: Nonce() {} ~Nonce(); + /// @returns the singleton instance. + static Nonce& singleton(); + /// Reads the last seed from the seed file. + void initialiseIfNeeded(); + /// @returns the next nonce. + h256 next(); + /// Stores the current seed in the seed file. + void commit(); + /// @returns the path of the seed file. + static std::string seedFile(); + + /// Mutex for the singleton object. + /// @note Every access to any private function has to be guarded by this mutex. + static std::mutex s_x; + + h256 m_value; }; } diff --git a/libdevcrypto/Exceptions.h b/libdevcrypto/Exceptions.h index 675213d8b..858374bda 100644 --- a/libdevcrypto/Exceptions.h +++ b/libdevcrypto/Exceptions.h @@ -29,7 +29,7 @@ namespace crypto { /// Rare malfunction of cryptographic functions. -DEV_SIMPLE_EXCEPTION_RLP(CryptoException); +DEV_SIMPLE_EXCEPTION(CryptoException); } } From 0fccf207acf51517a56c2328d6f48ae0d8a04c3f Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 16 Jun 2015 14:02:09 +0200 Subject: [PATCH 085/103] Fixed parameter. --- libdevcrypto/SecretStore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 86e378589..6423269f9 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -204,7 +204,7 @@ bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function Date: Wed, 17 Jun 2015 16:35:28 +0200 Subject: [PATCH 086/103] Fix to correctly write nonce during tests. --- libdevcrypto/Common.cpp | 29 +++++++++++++++++++++-------- libdevcrypto/Common.h | 10 ++++++++-- test/TestUtils.cpp | 11 +++++++++++ test/TestUtils.h | 9 +++++++++ test/libdevcrypto/SecretStore.cpp | 6 +++++- test/libdevcrypto/crypto.cpp | 5 +++++ 6 files changed, 59 insertions(+), 11 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 94f78b1e2..66f211933 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -255,6 +255,7 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash) } mutex Nonce::s_x; +static string s_seedFile; h256 Nonce::get() { @@ -264,15 +265,23 @@ h256 Nonce::get() return Nonce::singleton().next(); } -// get: Called for the first time: read seed hash from file (or generate) -// before destruction: increment current value and store +void Nonce::reset() +{ + Guard l(Nonce::s_x); + Nonce::singleton().resetInternal(); +} + +void Nonce::setSeedFilePath(string const& _filePath) +{ + s_seedFile = _filePath; +} Nonce::~Nonce() { Guard l(Nonce::s_x); - // These might throw. - next(); - commit(); + if (m_value) + // this might throw + resetInternal(); } Nonce& Nonce::singleton() @@ -312,13 +321,17 @@ h256 Nonce::next() return m_value; } -void Nonce::commit() +void Nonce::resetInternal() { // this might throw + next(); writeFile(seedFile(), m_value.asBytes()); + m_value = h256(); } -string Nonce::seedFile() +string const& Nonce::seedFile() { - return getDataDir() + "/seed"; + if (s_seedFile.empty()) + s_seedFile = getDataDir() + "/seed"; + return s_seedFile; } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 96f525e49..b3d2649b8 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -185,7 +185,13 @@ h256 kdf(Secret const& _priv, h256 const& _hash); */ struct Nonce { + /// Returns the next nonce (might be read from a file). static h256 get(); + /// Stores the current nonce in a file and resets Nonce to the uninitialised state. + static void reset(); + /// Sets the location of the seed file to a non-default place. Used for testing. + static void setSeedFilePath(std::string const& _filePath); + private: Nonce() {} ~Nonce(); @@ -196,9 +202,9 @@ private: /// @returns the next nonce. h256 next(); /// Stores the current seed in the seed file. - void commit(); + void resetInternal(); /// @returns the path of the seed file. - static std::string seedFile(); + static std::string const& seedFile(); /// Mutex for the singleton object. /// @note Every access to any private function has to be guarded by this mutex. diff --git a/test/TestUtils.cpp b/test/TestUtils.cpp index ff5169d55..bd603a61f 100644 --- a/test/TestUtils.cpp +++ b/test/TestUtils.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -116,3 +117,13 @@ void ParallelClientBaseFixture::enumerateClients(std::function #include #include +#include #include #include @@ -78,5 +79,13 @@ struct JsonRpcFixture: public ClientBaseFixture }; +struct MoveNonceToTempDir +{ + MoveNonceToTempDir(); + ~MoveNonceToTempDir(); +private: + TransientDirectory m_dir; +}; + } } diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp index 80d850a7c..dafad28a8 100644 --- a/test/libdevcrypto/SecretStore.cpp +++ b/test/libdevcrypto/SecretStore.cpp @@ -29,12 +29,16 @@ #include #include #include "MemTrie.h" -#include "../TestHelper.h" +#include +#include using namespace std; using namespace dev; +using namespace dev::test; namespace js = json_spirit; +BOOST_GLOBAL_FIXTURE( MoveNonceToTempDir ); + BOOST_AUTO_TEST_SUITE(KeyStore) BOOST_AUTO_TEST_CASE(basic_tests) diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index 497887145..31589c3ce 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -31,12 +31,16 @@ #include #include #include +#include using namespace std; using namespace dev; +using namespace dev::test; using namespace dev::crypto; using namespace CryptoPP; +BOOST_GLOBAL_FIXTURE( MoveNonceToTempDir ); + BOOST_AUTO_TEST_SUITE(devcrypto) static Secp256k1 s_secp256k1; @@ -45,6 +49,7 @@ static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1()); static CryptoPP::DL_GroupParameters_EC s_params(s_curveOID); static CryptoPP::DL_GroupParameters_EC::EllipticCurve s_curve(s_params.GetCurve()); + BOOST_AUTO_TEST_CASE(sha3general) { BOOST_REQUIRE_EQUAL(sha3(""), h256("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); From db803547fa97dff1699ffc9802ee1b940e1a522f Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 18 Jun 2015 12:20:55 +0200 Subject: [PATCH 087/103] Fixes. --- libdevcrypto/Common.cpp | 4 ++-- libdevcrypto/SecretStore.cpp | 12 ++---------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 66f211933..af61a1dd5 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -189,7 +189,7 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, _salt.size(), _iterations ) != _iterations) - BOOST_THROW_EXCEPTION(CryptoException()); + BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); return ret; } @@ -207,7 +207,7 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin ret.data(), ret.size() ) != 0) - BOOST_THROW_EXCEPTION(CryptoException()); + BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed.")); return ret; } diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 6423269f9..aeb06f11b 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -112,8 +112,6 @@ h128 SecretStore::importSecret(bytes const& _s, string const& _pass) { h128 r; EncryptedKey key{encrypt(_s, _pass), string()}; - if (!key.encryptedKey.empty()) - BOOST_THROW_EXCEPTION(crypto::CryptoException()); r = h128::random(); m_cached[r] = _s; m_keys[r] = move(key); @@ -243,10 +241,7 @@ string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) bytes derivedKey = deriveNewKey(_pass, _kdf, ret); if (derivedKey.empty()) - { - cwarn << "Key derivation failed."; - return string(); - } + BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key derivation failed.")); ret["cipher"] = "aes-128-ctr"; h128 key(derivedKey, h128::AlignLeft); @@ -260,10 +255,7 @@ string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf) // cipher text bytes cipherText = encryptSymNoAuth(key, iv, &_v); if (cipherText.empty()) - { - cwarn << "Key encryption failed."; - return string(); - } + BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key encryption failed.")); ret["ciphertext"] = toHex(cipherText); // and mac. From 032ebde3ecd0a75c9ae9687b3186044ca66b6854 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 18 Jun 2015 12:31:58 +0200 Subject: [PATCH 088/103] avoid network tests when --nonetwork is set --- test/TestHelper.cpp | 7 ++++--- test/TestHelper.h | 3 ++- test/libethereum/stateOriginal.cpp | 6 +++++- test/libp2p/capability.cpp | 4 ++++ test/libp2p/net.cpp | 26 ++++++++++++++++++++++++++ test/libp2p/peer.cpp | 12 +++++++++--- test/libwhisper/whisperTopic.cpp | 11 +++++++++++ 7 files changed, 61 insertions(+), 8 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 4e1ad92b4..6c1db8eea 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -754,8 +754,10 @@ Options::Options() checkState = true; else if (arg == "--wallet") wallet = true; - else if (arg == "--network") - network = true; + else if (arg == "--nonetwork") + nonetwork = true; + else if (arg == "--nodag") + nodag = true; else if (arg == "--all") { performance = true; @@ -764,7 +766,6 @@ Options::Options() inputLimits = true; bigData = true; wallet = true; - network = true; } else if (arg == "--singletest" && i + 1 < argc) { diff --git a/test/TestHelper.h b/test/TestHelper.h index ab52a550c..c21429ef4 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -223,7 +223,8 @@ public: bool inputLimits = false; bool bigData = false; bool wallet = false; - bool network = false; + bool nonetwork = false; + bool nodag = false; /// @} /// Get reference to options diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e7a078182..ac2f893de 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -27,7 +27,8 @@ #include #include #include -#include "../TestHelper.h" +#include + using namespace std; using namespace dev; using namespace dev::eth; @@ -48,6 +49,9 @@ BOOST_AUTO_TEST_CASE(Basic) BOOST_AUTO_TEST_CASE(Complex) { + if (test::Options::get().nodag) + return; + cnote << "Testing State..."; KeyPair me = sha3("Gav Wood"); diff --git a/test/libp2p/capability.cpp b/test/libp2p/capability.cpp index fa8592bdd..13ae4d498 100644 --- a/test/libp2p/capability.cpp +++ b/test/libp2p/capability.cpp @@ -27,6 +27,7 @@ along with cpp-ethereum. If not, see . #include #include #include +#include using namespace std; using namespace dev; @@ -98,6 +99,9 @@ BOOST_FIXTURE_TEST_SUITE(p2pCapability, P2PFixture) BOOST_AUTO_TEST_CASE(capability) { + if (test::Options::get().nonetwork) + return; + VerbosityHolder verbosityHolder(10); cnote << "Testing Capability..."; diff --git a/test/libp2p/net.cpp b/test/libp2p/net.cpp index a31537b98..8c652b479 100644 --- a/test/libp2p/net.cpp +++ b/test/libp2p/net.cpp @@ -26,6 +26,8 @@ #include #include #include +#include + using namespace std; using namespace dev; using namespace dev::p2p; @@ -153,6 +155,9 @@ public: BOOST_AUTO_TEST_CASE(requestTimeout) { + if (test::Options::get().nonetwork) + return; + using TimePoint = std::chrono::steady_clock::time_point; using RequestTimeout = std::pair; @@ -220,6 +225,9 @@ BOOST_AUTO_TEST_CASE(isIPAddressType) BOOST_AUTO_TEST_CASE(v2PingNodePacket) { + if (test::Options::get().nonetwork) + return; + // test old versino of pingNode packet w/new RLPStream s; s.appendList(3); s << "1.1.1.1" << 30303 << std::chrono::duration_cast((std::chrono::system_clock::now() + chrono::seconds(60)).time_since_epoch()).count(); @@ -231,6 +239,9 @@ BOOST_AUTO_TEST_CASE(v2PingNodePacket) BOOST_AUTO_TEST_CASE(neighboursPacketLength) { + if (test::Options::get().nonetwork) + return; + KeyPair k = KeyPair::create(); std::vector> testNodes(TestNodeTable::createTestNodes(16)); bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); @@ -256,6 +267,9 @@ BOOST_AUTO_TEST_CASE(neighboursPacketLength) BOOST_AUTO_TEST_CASE(neighboursPacket) { + if (test::Options::get().nonetwork) + return; + KeyPair k = KeyPair::create(); std::vector> testNodes(TestNodeTable::createTestNodes(16)); bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); @@ -291,6 +305,9 @@ BOOST_AUTO_TEST_CASE(test_findnode_neighbours) BOOST_AUTO_TEST_CASE(kademlia) { + if (test::Options::get().nonetwork) + return; + // Not yet a 'real' test. TestNodeTableHost node(8); node.start(); @@ -324,6 +341,9 @@ BOOST_AUTO_TEST_CASE(kademlia) BOOST_AUTO_TEST_CASE(udpOnce) { + if (test::Options::get().nonetwork) + return; + UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65})); TestUDPSocket a; a.m_socket->connect(); a.start(); a.m_socket->send(d); @@ -337,6 +357,9 @@ BOOST_AUTO_TEST_SUITE(netTypes) BOOST_AUTO_TEST_CASE(unspecifiedNode) { + if (test::Options::get().nonetwork) + return; + Node n = UnspecifiedNode; BOOST_REQUIRE(!n); @@ -350,6 +373,9 @@ BOOST_AUTO_TEST_CASE(unspecifiedNode) BOOST_AUTO_TEST_CASE(nodeTableReturnsUnspecifiedNode) { + if (test::Options::get().nonetwork) + return; + ba::io_service io; NodeTable t(io, KeyPair::create(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30303, 30303)); if (Node n = t.node(NodeId())) diff --git a/test/libp2p/peer.cpp b/test/libp2p/peer.cpp index 5fea9225e..8f37ce164 100644 --- a/test/libp2p/peer.cpp +++ b/test/libp2p/peer.cpp @@ -40,7 +40,7 @@ BOOST_FIXTURE_TEST_SUITE(p2p, P2PFixture) BOOST_AUTO_TEST_CASE(host) { - if (!test::Options::get().network) + if (test::Options::get().nonetwork) return; VerbosityHolder sentinel(10); @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(host) BOOST_AUTO_TEST_CASE(networkConfig) { - if (!test::Options::get().network) + if (test::Options::get().nonetwork) return; Host save("Test", NetworkPreferences(false)); @@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(networkConfig) BOOST_AUTO_TEST_CASE(saveNodes) { - if (!test::Options::get().network) + if (test::Options::get().nonetwork) return; VerbosityHolder reduceVerbosity(2); @@ -145,6 +145,9 @@ BOOST_FIXTURE_TEST_SUITE(p2pPeer, P2PFixture) BOOST_AUTO_TEST_CASE(requirePeer) { + if (test::Options::get().nonetwork) + return; + VerbosityHolder reduceVerbosity(10); const char* const localhost = "127.0.0.1"; @@ -197,6 +200,9 @@ BOOST_AUTO_TEST_SUITE(peerTypes) BOOST_AUTO_TEST_CASE(emptySharedPeer) { + if (test::Options::get().nonetwork) + return; + shared_ptr p; BOOST_REQUIRE(!p); diff --git a/test/libwhisper/whisperTopic.cpp b/test/libwhisper/whisperTopic.cpp index b5f5cd7d3..f09705ccb 100644 --- a/test/libwhisper/whisperTopic.cpp +++ b/test/libwhisper/whisperTopic.cpp @@ -25,6 +25,8 @@ #include #include #include +#include + using namespace std; using namespace dev; using namespace dev::p2p; @@ -40,6 +42,9 @@ BOOST_FIXTURE_TEST_SUITE(whisper, P2PFixture) BOOST_AUTO_TEST_CASE(topic) { + if (test::Options::get().nonetwork) + return; + cnote << "Testing Whisper..."; VerbosityHolder setTemporaryLevel(0); @@ -103,6 +108,9 @@ BOOST_AUTO_TEST_CASE(topic) BOOST_AUTO_TEST_CASE(forwarding) { + if (test::Options::get().nonetwork) + return; + cnote << "Testing Whisper forwarding..."; VerbosityHolder setTemporaryLevel(0); @@ -203,6 +211,9 @@ BOOST_AUTO_TEST_CASE(forwarding) BOOST_AUTO_TEST_CASE(asyncforwarding) { + if (test::Options::get().nonetwork) + return; + cnote << "Testing Whisper async forwarding..."; VerbosityHolder setTemporaryLevel(2); From 7afcafa127a9ba80a97ae4f79a36d63ae933c9ad Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 18 Jun 2015 14:41:06 +0200 Subject: [PATCH 089/103] Tests for constructor arguments "from outside". --- test/libsolidity/SolidityEndToEndTest.cpp | 28 ++++++++++++++++--- test/libsolidity/solidityExecutionFramework.h | 18 +++++++++--- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 66a8f8820..7ee259abe 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1726,7 +1726,7 @@ BOOST_AUTO_TEST_CASE(fixed_bytes_in_calls) BOOST_CHECK(callContractFunction("callHelper(bytes2,bool)", string("\0a", 2), true) == encodeArgs(string("\0a\0\0\0", 5))); } -BOOST_AUTO_TEST_CASE(constructor_arguments) +BOOST_AUTO_TEST_CASE(constructor_arguments_internal) { char const* sourceCode = R"( contract Helper { @@ -1749,8 +1749,28 @@ BOOST_AUTO_TEST_CASE(constructor_arguments) function getName() returns (bytes3 ret) { return h.getName(); } })"; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("getFlag()") == encodeArgs(true)); - BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); + BOOST_CHECK(callContractFunction("getFlag()") == encodeArgs(true)); + BOOST_CHECK(callContractFunction("getName()") == encodeArgs("abc")); +} + +BOOST_AUTO_TEST_CASE(constructor_arguments_external) +{ + char const* sourceCode = R"( + contract Main { + bytes3 name; + bool flag; + + function Main(bytes3 x, bool f) { + name = x; + flag = f; + } + function getName() returns (bytes3 ret) { return name; } + function getFlag() returns (bool ret) { return flag; } + } + )"; + compileAndRun(sourceCode, 0, "Main", encodeArgs("abc", true)); + BOOST_CHECK(callContractFunction("getFlag()") == encodeArgs(true)); + BOOST_CHECK(callContractFunction("getName()") == encodeArgs("abc")); } BOOST_AUTO_TEST_CASE(functions_called_by_constructor) @@ -4166,7 +4186,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) } } )"; - BOOST_CHECK(compileAndRunWthoutCheck(sourceCode, 0, "A").empty()); + BOOST_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "A").empty()); } BOOST_AUTO_TEST_CASE(positive_integers_to_signed) diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 4ba229815..0079d82b6 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -42,19 +42,29 @@ class ExecutionFramework public: ExecutionFramework() { g_logVerbosity = 0; } - bytes const& compileAndRunWthoutCheck(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + bytes const& compileAndRunWithoutCheck( + std::string const& _sourceCode, + u256 const& _value = 0, + std::string const& _contractName = "", + bytes const& _arguments = bytes() + ) { m_compiler.reset(false, m_addStandardSources); m_compiler.addSource("", _sourceCode); ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed"); bytes code = m_compiler.getBytecode(_contractName); - sendMessage(code, true, _value); + sendMessage(code + _arguments, true, _value); return m_output; } - bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + bytes const& compileAndRun( + std::string const& _sourceCode, + u256 const& _value = 0, + std::string const& _contractName = "", + bytes const& _arguments = bytes() + ) { - compileAndRunWthoutCheck(_sourceCode, _value, _contractName); + compileAndRunWithoutCheck(_sourceCode, _value, _contractName, _arguments); BOOST_REQUIRE(!m_output.empty()); return m_output; } From d8eb362d32f63b250d385d02d92e5ead30ee8488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Jun 2015 15:15:55 +0200 Subject: [PATCH 090/103] VM: refactor and fix undefined behavior around data to memory copy. std::memcpy and std::memset cannot be called with invalid pointers even when the size to be copied/set is 0. --- libevm/VM.cpp | 58 +++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 36fba6e43..062581563 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -202,6 +202,24 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) return nextPC; }; + auto copyDataToMemory = [](bytesConstRef _data, decltype(m_stack)& _stack, decltype(m_temp)& _memory) + { + auto offset = static_cast(_stack.back()); + _stack.pop_back(); + bigint bigIndex = _stack.back(); + auto index = static_cast(bigIndex); + _stack.pop_back(); + auto size = static_cast(_stack.back()); + _stack.pop_back(); + + auto sizeToBeCopied = bigIndex + size > _data.size() ? _data.size() < bigIndex ? 0 : _data.size() - index : size; + + if (sizeToBeCopied > 0) + std::memcpy(_memory.data() + offset, _data.data() + index, sizeToBeCopied); + if (size - sizeToBeCopied > 0) + std::memset(_memory.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied); + }; + m_steps = 0; for (auto nextPC = m_curPC + 1; true; m_curPC = nextPC, nextPC = m_curPC + 1, ++m_steps) { @@ -364,44 +382,16 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = _ext.codeAt(asAddress(m_stack.back())).size(); break; case Instruction::CALLDATACOPY: + copyDataToMemory(_ext.data, m_stack, m_temp); + break; case Instruction::CODECOPY: + copyDataToMemory(&_ext.code, m_stack, m_temp); + break; case Instruction::EXTCODECOPY: { - Address a; - if (inst == Instruction::EXTCODECOPY) - { - a = asAddress(m_stack.back()); - m_stack.pop_back(); - } - unsigned offset = (unsigned)m_stack.back(); - m_stack.pop_back(); - u256 index = m_stack.back(); - m_stack.pop_back(); - unsigned size = (unsigned)m_stack.back(); + auto a = asAddress(m_stack.back()); m_stack.pop_back(); - unsigned sizeToBeCopied; - switch(inst) - { - case Instruction::CALLDATACOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.data.size() ? (u256)_ext.data.size() < index ? 0 : _ext.data.size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.data.data() + (unsigned)index, sizeToBeCopied); - break; - case Instruction::CODECOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.code.size() ? (u256)_ext.code.size() < index ? 0 : _ext.code.size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.code.data() + (unsigned)index, sizeToBeCopied); - break; - case Instruction::EXTCODECOPY: - sizeToBeCopied = index + (bigint)size > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < index ? 0 : _ext.codeAt(a).size() - (unsigned)index : size; - memcpy(m_temp.data() + offset, _ext.codeAt(a).data() + (unsigned)index, sizeToBeCopied); - break; - default: - // this is unreachable, but if someone introduces a bug in the future, he may get here. - assert(false); - BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("CALLDATACOPY, CODECOPY or EXTCODECOPY instruction requested.")); - break; - } - memset(m_temp.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied); - break; + copyDataToMemory(&_ext.codeAt(a), m_stack, m_temp); } case Instruction::GASPRICE: m_stack.push_back(_ext.gasPrice); From af93ec370d3d76eda925644b72e6d4a96c0524a9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 18 Jun 2015 14:41:24 +0200 Subject: [PATCH 091/103] Safe file writing and some tests. --- libdevcore/CommonIO.cpp | 24 ++++-- libdevcore/CommonIO.h | 8 +- libdevcrypto/SecretStore.cpp | 6 +- test/libdevcrypto/SecretStore.cpp | 132 +++++++++++++++++++++++++++++- 4 files changed, 155 insertions(+), 15 deletions(-) diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index d0a1b8c5b..cfe7b8a6b 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -23,13 +23,14 @@ #include #include #include -#include "Exceptions.h" #include #ifdef _WIN32 #include #else #include #endif +#include +#include "Exceptions.h" using namespace std; using namespace dev; @@ -95,12 +96,23 @@ string dev::contentsString(string const& _file) return contentsGeneric(_file); } -void dev::writeFile(std::string const& _file, bytesConstRef _data) +void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename) { - ofstream s(_file, ios::trunc | ios::binary); - s.write(reinterpret_cast(_data.data()), _data.size()); - if (!s) - BOOST_THROW_EXCEPTION(FileError()); + if (_writeDeleteRename) + { + namespace fs = boost::filesystem; + fs::path tempPath = fs::unique_path(_file + "-%%%%%%"); + writeFile(tempPath.string(), _data, false); + // will delete _file if it exists + fs::rename(tempPath, _file); + } + else + { + ofstream s(_file, ios::trunc | ios::binary); + s.write(reinterpret_cast(_data.data()), _data.size()); + if (!s) + BOOST_THROW_EXCEPTION(FileError()); + } } std::string dev::getPassword(std::string const& _prompt) diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h index cc2ef7484..da0f6a963 100644 --- a/libdevcore/CommonIO.h +++ b/libdevcore/CommonIO.h @@ -57,10 +57,12 @@ bytesRef contentsNew(std::string const& _file, bytesRef _dest = bytesRef()); /// Write the given binary data into the given file, replacing the file if it pre-exists. /// Throws exception on error. -void writeFile(std::string const& _file, bytesConstRef _data); +/// @param _writeDeleteRename useful not to lose any data: If set, first writes to another file in +/// the same directory and then moves that file. +void writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename = false); /// Write the given binary data into the given file, replacing the file if it pre-exists. -inline void writeFile(std::string const& _file, bytes const& _data) { writeFile(_file, bytesConstRef(&_data)); } -inline void writeFile(std::string const& _file, std::string const& _data) { writeFile(_file, bytesConstRef(_data)); } +inline void writeFile(std::string const& _file, bytes const& _data, bool _writeDeleteRename = false) { writeFile(_file, bytesConstRef(&_data), _writeDeleteRename); } +inline void writeFile(std::string const& _file, std::string const& _data, bool _writeDeleteRename = false) { writeFile(_file, bytesConstRef(_data), _writeDeleteRename); } /// Nicely renders the given bytes to a string, optionally as HTML. /// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line. diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index aeb06f11b..a7a16a1b8 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -88,8 +88,7 @@ static js::mValue upgraded(string const& _s) SecretStore::SecretStore(string const& _path): m_path(_path) { - if (!m_path.empty()) - load(); + load(); } bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const @@ -136,9 +135,6 @@ void SecretStore::clearCache() const void SecretStore::save(string const& _keysPath) { - if (_keysPath.empty()) - return; - fs::path p(_keysPath); fs::create_directories(p); for (auto& k: m_keys) diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp index dafad28a8..c9d5131d0 100644 --- a/test/libdevcrypto/SecretStore.cpp +++ b/test/libdevcrypto/SecretStore.cpp @@ -36,6 +36,7 @@ using namespace dev; using namespace dev::test; namespace js = json_spirit; +namespace fs = boost::filesystem; BOOST_GLOBAL_FIXTURE( MoveNonceToTempDir ); @@ -56,7 +57,8 @@ BOOST_AUTO_TEST_CASE(basic_tests) { cnote << i.first; js::mObject& o = i.second.get_obj(); - SecretStore store(""); + TransientDirectory tmpDir; + SecretStore store(tmpDir.path()); h128 u = store.readKeyContent(js::write_string(o["json"], false)); cdebug << "read uuid" << u; bytes s = store.secret(u, [&](){ return o["password"].get_str(); }); @@ -65,4 +67,132 @@ BOOST_AUTO_TEST_CASE(basic_tests) } } +BOOST_AUTO_TEST_CASE(import_key_from_file) +{ + // Imports a key from an external file. Tests that the imported key is there + // and that the external file is not deleted. + TransientDirectory importDir; + string importFile = importDir.path() + "/import.json"; + TransientDirectory storeDir; + string keyData = R"({ + "version": 3, + "crypto": { + "ciphertext": "d69313b6470ac1942f75d72ebf8818a0d484ac78478a132ee081cd954d6bd7a9", + "cipherparams": { "iv": "ffffffffffffffffffffffffffffffff" }, + "kdf": "pbkdf2", + "kdfparams": { "dklen": 32, "c": 262144, "prf": "hmac-sha256", "salt": "c82ef14476014cbf438081a42709e2ed" }, + "mac": "cf6bfbcc77142a22c4a908784b4a16f1023a1d0e2aff404c20158fa4f1587177", + "cipher": "aes-128-ctr", + "version": 1 + }, + "id": "abb67040-8dbe-0dad-fc39-2b082ef0ee5f" + })"; + string password = "bar"; + string priv = "0202020202020202020202020202020202020202020202020202020202020202"; + writeFile(importFile, keyData); + + h128 uuid; + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 0); + uuid = store.importKey(importFile); + BOOST_CHECK(!!uuid); + BOOST_CHECK(contentsString(importFile) == keyData); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + } + fs::remove(importFile); + // now do it again to check whether SecretStore properly stored it on disk + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + } +} + +BOOST_AUTO_TEST_CASE(import_secret) +{ + for (string const& password: {"foobar", ""}) + { + TransientDirectory storeDir; + string priv = "0202020202020202020202020202020202020202020202020202020202020202"; + + h128 uuid; + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 0); + uuid = store.importSecret(fromHex(priv), password); + BOOST_CHECK(!!uuid); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + } + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + } + } +} + +BOOST_AUTO_TEST_CASE(wrong_password) +{ + TransientDirectory storeDir; + SecretStore store(storeDir.path()); + string password = "foobar"; + string priv = "0202020202020202020202020202020202020202020202020202020202020202"; + + h128 uuid; + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 0); + uuid = store.importSecret(fromHex(priv), password); + BOOST_CHECK(!!uuid); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + // password will not be queried + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }))); + } + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + BOOST_CHECK(store.secret(uuid, [&](){ return "abcdefg"; }).empty()); + } +} + +BOOST_AUTO_TEST_CASE(recode) +{ + TransientDirectory storeDir; + SecretStore store(storeDir.path()); + string password = "foobar"; + string changedPassword = "abcdefg"; + string priv = "0202020202020202020202020202020202020202020202020202020202020202"; + + h128 uuid; + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 0); + uuid = store.importSecret(fromHex(priv), password); + BOOST_CHECK(!!uuid); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }))); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + } + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + BOOST_CHECK(store.secret(uuid, [&](){ return "abcdefg"; }).empty()); + BOOST_CHECK(store.recode(uuid, changedPassword, [&](){ return password; })); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + store.clearCache(); + BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + } + { + SecretStore store(storeDir.path()); + BOOST_CHECK_EQUAL(store.keys().size(), 1); + BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty()); + BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }))); + } +} + BOOST_AUTO_TEST_SUITE_END() From 6b3fd2d3cae85bd310f46f5929b110a579684c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Jun 2015 14:01:43 +0200 Subject: [PATCH 092/103] Small override & std::move fixes. --- libethereum/BlockChain.cpp | 2 +- libethereum/EthereumHost.h | 6 +++--- libweb3jsonrpc/JsonHelper.h | 2 +- mix/MixClient.h | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 10256900d..92cc2733f 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -1122,6 +1122,6 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function; using UncleHashes = h256s; diff --git a/mix/MixClient.h b/mix/MixClient.h index afb9f5430..1172bffbd 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -59,6 +59,7 @@ public: dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; dev::eth::ExecutionResult create(Address const& _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock, eth::FudgeFactor _ff = eth::FudgeFactor::Strict) override; + using ClientBase::submitTransaction; void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto); Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto); dev::eth::ExecutionResult call(Address const& _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto, eth::FudgeFactor _ff = eth::FudgeFactor::Strict); From c7b257acde69e42ca2448bd0cb535470e5992db8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 18 Jun 2015 16:35:25 +0200 Subject: [PATCH 093/103] Fix and test for not really recursive structs. Fixes #2223. --- libsolidity/AST.cpp | 33 +++++++++++-------- .../SolidityNameAndTypeResolution.cpp | 11 +++++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 6d6a13cff..7333c024a 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -434,23 +435,29 @@ void StructDefinition::checkMemberTypes() const void StructDefinition::checkRecursion() const { - set definitionsSeen; - vector queue = {this}; - while (!queue.empty()) + using StructPointer = StructDefinition const*; + using StructPointersSet = set; + function check = [&](StructPointer _struct, StructPointersSet const& _parents) { - StructDefinition const* def = queue.back(); - queue.pop_back(); - if (definitionsSeen.count(def)) - BOOST_THROW_EXCEPTION(ParserError() << errinfo_sourceLocation(def->getLocation()) - << errinfo_comment("Recursive struct definition.")); - definitionsSeen.insert(def); - for (ASTPointer const& member: def->getMembers()) + if (_parents.count(_struct)) + BOOST_THROW_EXCEPTION( + ParserError() << + errinfo_sourceLocation(_struct->getLocation()) << + errinfo_comment("Recursive struct definition.") + ); + set parents = _parents; + parents.insert(_struct); + for (ASTPointer const& member: _struct->getMembers()) if (member->getType()->getCategory() == Type::Category::Struct) { - UserDefinedTypeName const& typeName = dynamic_cast(*member->getTypeName()); - queue.push_back(&dynamic_cast(*typeName.getReferencedDeclaration())); + auto const& typeName = dynamic_cast(*member->getTypeName()); + check( + &dynamic_cast(*typeName.getReferencedDeclaration()), + parents + ); } - } + }; + check(this, {}); } TypePointer EnumDefinition::getType(ContractDefinition const*) const diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index fced12848..afa8b727f 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -190,6 +190,17 @@ BOOST_AUTO_TEST_CASE(struct_definition_indirectly_recursive) BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError); } +BOOST_AUTO_TEST_CASE(struct_definition_not_really_recursive) +{ + char const* text = R"( + contract test { + struct s1 { uint a; } + struct s2 { s1 x; s1 y; } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + BOOST_AUTO_TEST_CASE(struct_definition_recursion_via_mapping) { char const* text = "contract test {\n" From d42f404b12f9d63de2e00fc7caf122e87d971724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 18 Jun 2015 16:37:23 +0200 Subject: [PATCH 094/103] Fix int comparison. --- libevm/VM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 062581563..2b2ada0ae 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -212,11 +212,11 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) auto size = static_cast(_stack.back()); _stack.pop_back(); - auto sizeToBeCopied = bigIndex + size > _data.size() ? _data.size() < bigIndex ? 0 : _data.size() - index : size; + size_t sizeToBeCopied = bigIndex + size > _data.size() ? _data.size() < bigIndex ? 0 : _data.size() - index : size; if (sizeToBeCopied > 0) std::memcpy(_memory.data() + offset, _data.data() + index, sizeToBeCopied); - if (size - sizeToBeCopied > 0) + if (size > sizeToBeCopied) std::memset(_memory.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied); }; From f2dd242f5bf31f27c05ded8c36a4e7c1a9f69ed9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 18 Jun 2015 16:49:38 +0200 Subject: [PATCH 095/103] Fixed build errors. --- test/libdevcrypto/SecretStore.cpp | 2 +- test/libdevcrypto/crypto.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/libdevcrypto/SecretStore.cpp b/test/libdevcrypto/SecretStore.cpp index c9d5131d0..30bff49d9 100644 --- a/test/libdevcrypto/SecretStore.cpp +++ b/test/libdevcrypto/SecretStore.cpp @@ -38,7 +38,7 @@ using namespace dev::test; namespace js = json_spirit; namespace fs = boost::filesystem; -BOOST_GLOBAL_FIXTURE( MoveNonceToTempDir ); +BOOST_GLOBAL_FIXTURE( MoveNonceToTempDir ) BOOST_AUTO_TEST_SUITE(KeyStore) diff --git a/test/libdevcrypto/crypto.cpp b/test/libdevcrypto/crypto.cpp index 31589c3ce..1a0537ccd 100644 --- a/test/libdevcrypto/crypto.cpp +++ b/test/libdevcrypto/crypto.cpp @@ -39,7 +39,7 @@ using namespace dev::test; using namespace dev::crypto; using namespace CryptoPP; -BOOST_GLOBAL_FIXTURE( MoveNonceToTempDir ); +BOOST_GLOBAL_FIXTURE( MoveNonceToTempDir ) BOOST_AUTO_TEST_SUITE(devcrypto) @@ -49,7 +49,6 @@ static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1()); static CryptoPP::DL_GroupParameters_EC s_params(s_curveOID); static CryptoPP::DL_GroupParameters_EC::EllipticCurve s_curve(s_params.GetCurve()); - BOOST_AUTO_TEST_CASE(sha3general) { BOOST_REQUIRE_EQUAL(sha3(""), h256("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); From 96d667baa814c0a2a0bfd16b97a8a403ce17d506 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 18 Jun 2015 17:00:03 +0200 Subject: [PATCH 096/103] don't grab unneeded blocks --- libethereum/BlockChainSync.cpp | 8 ++++---- libethereum/BlockChainSync.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index bcc7f72f3..eb4514731 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -402,7 +402,7 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ clog(NetWarn) << "Bad state: asking for Hashes yet not syncing!"; return; } - if (shouldGrabBlocks()) + if (shouldGrabBlocks(_peer)) { clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash << ", was" << host().latestBlockSent() << "]"; downloadMan().resetToChain(m_syncingNeededBlocks); @@ -504,10 +504,10 @@ bool PV60Sync::isSyncing(EthereumPeer* _peer) const return m_syncer == _peer; } -bool PV60Sync::shouldGrabBlocks() const +bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const { - auto td = m_syncingTotalDifficulty; - auto lh = m_syncingLatestHash; + auto td = _peer->m_totalDifficulty; + auto lh = _peer->m_latestHash; auto ctd = host().chain().details().totalDifficulty; if (m_syncingNeededBlocks.empty()) diff --git a/libethereum/BlockChainSync.h b/libethereum/BlockChainSync.h index 1337c5c90..e981a344e 100644 --- a/libethereum/BlockChainSync.h +++ b/libethereum/BlockChainSync.h @@ -174,8 +174,8 @@ private: /// Do we presently need syncing with this peer? bool needsSyncing(EthereumPeer* _peer) const; - /// Check whether the session should bother grabbing blocks. - bool shouldGrabBlocks() const; + /// Check whether the session should bother grabbing blocks from a peer. + bool shouldGrabBlocks(EthereumPeer* _peer) const; /// Attempt to begin syncing with the peer; first check the peer has a more difficlult chain to download, then start asking for hashes, then move to blocks void attemptSync(EthereumPeer* _peer); From 1cca1520440f9597de3c59c39e15ef57001a6e96 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Thu, 18 Jun 2015 17:56:14 +0200 Subject: [PATCH 097/103] clean windows build --- cmake/EthCompilerSettings.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index f91f20970..d33d44bac 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -38,7 +38,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # declare Windows XP requirement # undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions # define miniupnp static library - add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX /DMINIUPNP_STATICLIB) + add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 /wd4267 /wd4180 /wd4290 /wd4244 /wd4800 -D_WIN32_WINNT=0x0501 /DNOMINMAX /DMINIUPNP_STATICLIB) # disable empty object file warning set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification From c2c6119b3aac196cf31f7684dc7ca078d6134da4 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Thu, 18 Jun 2015 18:20:19 +0200 Subject: [PATCH 098/103] added a comment --- cmake/EthCompilerSettings.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index d33d44bac..85574d5f0 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -34,6 +34,11 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # disable unknown pragma warning (4068) # disable unsafe function warning (4996) # disable decorated name length exceeded, name was truncated (4503) + # disable conversion from 'size_t' to 'type', possible loss of data (4267) + # disable qualifier applied to function type has no meaning; ignored (4180) + # disable C++ exception specification ignored except to indicate a function is not __declspec(nothrow) (4290) + # disable conversion from 'type1' to 'type2', possible loss of data (4244) + # disable forcing value to bool 'true' or 'false' (performance warning) (4800) # disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests) # declare Windows XP requirement # undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions From e1f4c2e0e57ef599798005a04f176bcc2bb562eb Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 18 Jun 2015 23:29:44 +0200 Subject: [PATCH 099/103] use baseType to encode arrays --- mix/CodeModel.cpp | 12 +++++++++++- mix/CodeModel.h | 2 ++ mix/ContractCallDataEncoder.cpp | 32 ++++++-------------------------- mix/ContractCallDataEncoder.h | 2 +- mix/SolidityType.h | 1 + 5 files changed, 21 insertions(+), 28 deletions(-) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 1ca5d9160..8cb901a39 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -493,9 +493,18 @@ dev::bytes const& CodeModel::getStdContractCode(const QString& _contractName, co return m_compiledContracts.at(_contractName); } +void CodeModel::retrieveSubType(SolidityType& _wrapperType, dev::solidity::Type const* _type) +{ + if (_type->getCategory() == Type::Category::Array) + { + ArrayType const* arrayType = dynamic_cast(_type); + _wrapperType.baseType = std::make_shared(nodeType(arrayType->getBaseType().get())); + } +} + SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) { - SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, false, false, QString::fromStdString(_type->toString()), std::vector(), std::vector() }; + SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, false, false, QString::fromStdString(_type->toString()), std::vector(), std::vector(), nullptr }; if (!_type) return r; switch (_type->getCategory()) @@ -536,6 +545,7 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) r.count = static_cast(array->getLength()); r.dynamicSize = _type->isDynamicallySized(); r.array = true; + retrieveSubType(r, _type); } break; case Type::Category::Enum: diff --git a/mix/CodeModel.h b/mix/CodeModel.h index b9d06341d..7841c7142 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -224,6 +224,8 @@ public: Q_INVOKABLE void unregisterContractSrc(QString const& _documentId); /// Convert solidity type info to mix type static SolidityType nodeType(dev::solidity::Type const* _type); + /// Retrieve subtype + static void retrieveSubType(SolidityType& _wrapperType, dev::solidity::Type const* _type); /// Check if given location belongs to contract or function bool isContractOrFunctionLocation(dev::SourceLocation const& _location); /// Get funciton name by location diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 62cc39a04..da21869e4 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -37,24 +37,6 @@ using namespace dev; using namespace dev::solidity; using namespace dev::mix; -static QList extractDimension(QString const& _type) -{ - QList dim; - QRegExp dimExtract("(\\[[^\\]]*\\])"); - int pos = dimExtract.indexIn(_type); - while (pos != -1) - { - QString d = dimExtract.cap(0); - pos += d.length(); - pos = dimExtract.indexIn(_type, pos); - if (d == "[]") - dim.push_front(-1); - else - dim.push_front(d.replace("[", "").replace("]", "").toInt()); - } - return dim; -} - bytes ContractCallDataEncoder::encodedData() { bytes r(m_encodedData); @@ -81,25 +63,24 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end()); } -void ContractCallDataEncoder::encodeArray(QJsonArray const& _array, QList _dim, SolidityType const& _type, bytes& _content) +void ContractCallDataEncoder::encodeArray(QJsonArray const& _array, SolidityType const& _type, bytes& _content) { size_t offsetStart = _content.size(); - if (_dim[0] == -1) + if (_type.dynamicSize) { bytes count = bytes(32); toBigEndian((u256)_array.size(), count); _content += count; //reserved space for count } - _dim.pop_front(); int k = 0; for (QJsonValue const& c: _array) { if (c.isArray()) { - if (_dim[0] == -1) + if (_type.baseType->dynamicSize) m_dynamicOffsetMap.push_back(std::make_pair(m_dynamicData.size() + offsetStart + 32 + k * 32, m_dynamicData.size() + _content.size())); - encodeArray(c.toArray(), _dim, _type, _content); + encodeArray(c.toArray(), *_type.baseType, _content); } else { @@ -128,16 +109,15 @@ void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& } else if (_type.array) { - QList dim = extractDimension(_type. name); bytes content; size_t size = m_encodedData.size(); - if (dim.front() == -1) + if (_type.dynamicSize) { m_encodedData += bytes(32); // reserve space for offset m_staticOffsetMap.push_back(std::make_pair(size, m_dynamicData.size())); } QJsonDocument jsonDoc = QJsonDocument::fromJson(_data.toString().toUtf8()); - encodeArray(jsonDoc.array(), dim, _type, content); + encodeArray(jsonDoc.array(), _type, content); if (!_type.dynamicSize) m_encodedData.insert(m_encodedData.end(), content.begin(), content.end()); diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index e29cb92e0..be11a5772 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -71,7 +71,7 @@ private: QString toString(bool _b); QString toString(dev::bytes const& _b); bool asString(dev::bytes const& _b, QString& _str); - void encodeArray(QJsonArray const& _array, QList _dim, SolidityType const& _type, bytes& _content); + void encodeArray(QJsonArray const& _array, SolidityType const& _type, bytes& _content); QString toChar(dev::bytes const& _b); private: diff --git a/mix/SolidityType.h b/mix/SolidityType.h index 75f47e7fa..13f5c2ecd 100644 --- a/mix/SolidityType.h +++ b/mix/SolidityType.h @@ -57,6 +57,7 @@ struct SolidityType QString name; std::vector members; //for struct std::vector enumNames; //for enum + std::shared_ptr baseType; }; struct SolidityDeclaration From d2780c3d6a7cba52c454d2c1f567340db8e102f3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Jun 2015 10:21:27 +0800 Subject: [PATCH 100/103] Use right scoping. --- eth/main.cpp | 8 ++++---- libethcore/Common.h | 3 ++- libethcore/Params.cpp | 6 +++--- libjsconsole/JSConsole.cpp | 7 +++---- libjsconsole/JSConsole.h | 7 +++---- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 540cb8c4c..912de3245 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -835,12 +835,12 @@ int main(int argc, char** argv) cout << "Networking disabled. To start, use netstart or pass -b or a remote host." << endl; #if ETH_JSONRPC || !ETH_TRUE - shared_ptr jsonrpcServer; + shared_ptr jsonrpcServer; unique_ptr jsonrpcConnector; if (jsonrpc > -1) { jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); + jsonrpcServer = shared_ptr(new dev::WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; }); jsonrpcServer->StartListening(); if (jsonAdmin.empty()) @@ -996,7 +996,7 @@ int main(int argc, char** argv) if (jsonrpc < 0) jsonrpc = SensibleHttpPort; jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); + jsonrpcServer = shared_ptr(new dev::WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; }); jsonrpcServer->StartListening(); if (jsonAdmin.empty()) @@ -1744,7 +1744,7 @@ int main(int argc, char** argv) JSConsole console(web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager)); while (!g_exit) { - console.repl(); + console.readExpression(); stopMiningAfterXBlocks(c, n, mining); } #endif diff --git a/libethcore/Common.h b/libethcore/Common.h index 6f23cb0e8..18b7074b7 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -47,7 +47,8 @@ extern const unsigned c_databaseVersion; enum class Network { Olympic = 0, - Frontier = 1 + Frontier = 1, + Turbo = 2 }; extern const Network c_network; diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp index 916adf6ca..0fea39b30 100644 --- a/libethcore/Params.cpp +++ b/libethcore/Params.cpp @@ -31,12 +31,12 @@ namespace eth //--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json u256 const c_genesisDifficulty = 131072; u256 const c_maximumExtraDataSize = 1024; -u256 const c_genesisGasLimit = 3141592; -u256 const c_minGasLimit = 125000; +u256 const c_genesisGasLimit = c_network == Network::Turbo ? 100000000 : 3141592; +u256 const c_minGasLimit = c_network == Network::Turbo ? 100000000 : 125000; u256 const c_gasLimitBoundDivisor = 1024; u256 const c_minimumDifficulty = 131072; u256 const c_difficultyBoundDivisor = 2048; -u256 const c_durationLimit = c_network == Network::Olympic ? 8 : 12; +u256 const c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 12; //--- END: AUTOGENERATED FROM /feeStructure.json } diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp index d1f7c0264..29d547242 100644 --- a/libjsconsole/JSConsole.cpp +++ b/libjsconsole/JSConsole.cpp @@ -39,12 +39,11 @@ JSConsole::JSConsole(WebThreeDirect& _web3, shared_ptr const& _ac m_printer(m_engine) { m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); - m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector())); + (void)_web3; (void)_accounts; +// m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector())); } -JSConsole::~JSConsole() {} - -void JSConsole::repl() const +void JSConsole::readExpression() const { string cmd = ""; g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << flush; rl_forced_update_display(); }; diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h index b7aded4f3..2e5144a5d 100644 --- a/libjsconsole/JSConsole.h +++ b/libjsconsole/JSConsole.h @@ -25,7 +25,7 @@ #include #include -class WebThreeStubServer; +namespace dev { class WebThreeStubServer; } namespace jsonrpc { class AbstractServerConnector; } namespace dev @@ -39,15 +39,14 @@ class JSConsole { public: JSConsole(WebThreeDirect& _web3, std::shared_ptr const& _accounts); - ~JSConsole(); - void repl() const; + void readExpression() const; private: std::string promptForIndentionLevel(int _i) const; JSV8Engine m_engine; JSV8Printer m_printer; - std::unique_ptr m_jsonrpcServer; + std::unique_ptr m_jsonrpcServer; std::unique_ptr m_jsonrpcConnector; }; From b26b38c466f6edc2e742409be62b9eaa0e8a4b35 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Jun 2015 10:53:13 +0800 Subject: [PATCH 101/103] Blockchain sync trivial fixes. --- libethereum/BlockChainSync.cpp | 8 ++++---- libethereum/BlockChainSync.h | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index eb4514731..d7fd2c5ea 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -94,7 +94,7 @@ void BlockChainSync::onPeerStatus(EthereumPeer* _peer) DEV_INVARIANT_CHECK; } -unsigned BlockChainSync::estimateHashes() +unsigned BlockChainSync::estimateHashes() const { BlockInfo block = host().chain().info(); time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; @@ -478,12 +478,12 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ clog(NetWarn) << "Invalid state transition:" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); } -void PV60Sync::resetSyncFor(EthereumPeer* _peer, h256 _latestHash, u256 _td) +void PV60Sync::resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) { setNeedsSyncing(_peer, _latestHash, _td); } -void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 _latestHash, u256 _td) +void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) { _peer->m_latestHash = _latestHash; _peer->m_totalDifficulty = _td; @@ -707,7 +707,7 @@ void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) } unsigned knowns = 0; unsigned unknowns = 0; - for (auto h: _hashes) + for (auto const& h: _hashes) { _peer->addRating(1); DEV_GUARDED(_peer->x_knownBlocks) diff --git a/libethereum/BlockChainSync.h b/libethereum/BlockChainSync.h index e981a344e..7042c5a48 100644 --- a/libethereum/BlockChainSync.h +++ b/libethereum/BlockChainSync.h @@ -103,29 +103,29 @@ protected: virtual void pauseSync() = 0; /// Restart sync for given peer - virtual void resetSyncFor(EthereumPeer* _peer, h256 _latestHash, u256 _td) = 0; + virtual void resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) = 0; EthereumHost& host() { return m_host; } EthereumHost const& host() const { return m_host; } /// Estimates max number of hashes peers can give us. - unsigned estimateHashes(); + unsigned estimateHashes() const; /// Request blocks from peer if needed void requestBlocks(EthereumPeer* _peer); -private: - static char const* const s_stateNames[static_cast(SyncState::Size)]; - bool invariants() const override = 0; - EthereumHost& m_host; - HashDownloadMan m_hashMan; - protected: Handler m_bqRoomAvailable; mutable RecursiveMutex x_sync; SyncState m_state = SyncState::Idle; ///< Current sync state SyncState m_lastActiveState = SyncState::Idle; ///< Saved state before entering waiting queue mode unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. + +private: + static char const* const s_stateNames[static_cast(SyncState::Size)]; + bool invariants() const override = 0; + EthereumHost& m_host; + HashDownloadMan m_hashMan; }; @@ -159,7 +159,7 @@ public: void restartSync() override; void completeSync() override; void pauseSync() override; - void resetSyncFor(EthereumPeer* _peer, h256 _latestHash, u256 _td) override; + void resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) override; private: /// Transition sync state in a particular direction. @param _peer Peer that is responsible for state tranfer @@ -169,7 +169,7 @@ private: void resetNeedsSyncing(EthereumPeer* _peer) { setNeedsSyncing(_peer, h256(), 0); } /// Update peer syncing requirements state. - void setNeedsSyncing(EthereumPeer* _peer, h256 _latestHash, u256 _td); + void setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td); /// Do we presently need syncing with this peer? bool needsSyncing(EthereumPeer* _peer) const; From 210c86bb026fbfd0089dcf7cbfb14047cddede77 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Jun 2015 14:56:59 +0800 Subject: [PATCH 102/103] Backoff to attempt to deal with non-conformant clients. Reduce verbosity. --- libethereum/Client.cpp | 10 +++++----- libethereum/EthereumHost.cpp | 2 +- libethereum/EthereumPeer.cpp | 31 +++++++++++++++++++------------ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 8064e7e9f..7560f9165 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -673,10 +673,10 @@ void Client::onChainChanged(ImportRoute const& _ir) // insert transactions that we are declaring the dead part of the chain for (auto const& h: _ir.deadBlocks) { - clog(ClientNote) << "Dead block:" << h; + clog(ClientTrace) << "Dead block:" << h; for (auto const& t: m_bc.transactions(h)) { - clog(ClientNote) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); + clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry); } } @@ -684,10 +684,10 @@ void Client::onChainChanged(ImportRoute const& _ir) // remove transactions from m_tq nicely rather than relying on out of date nonce later on. for (auto const& h: _ir.liveBlocks) { - clog(ClientChat) << "Live block:" << h; + clog(ClientTrace) << "Live block:" << h; for (auto const& th: m_bc.transactionHashes(h)) { - clog(ClientNote) << "Safely dropping transaction " << th; + clog(ClientTrace) << "Safely dropping transaction " << th; m_tq.drop(th); } } @@ -723,7 +723,7 @@ void Client::onChainChanged(ImportRoute const& _ir) DEV_READ_GUARDED(x_postMine) for (auto const& t: m_postMine.pending()) { - clog(ClientNote) << "Resubmitting post-mine transaction " << t; + clog(ClientTrace) << "Resubmitting post-mine transaction " << t; auto ir = m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry); if (ir != ImportResult::Success) onTransactionQueueReady(); diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 152c20e69..f693ff768 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -296,7 +296,7 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) unsigned itemCount = _r.itemCount(); clog(NetAllDetail) << "Transactions (" << dec << itemCount << "entries)"; Guard l(_peer->x_knownTransactions); - for (unsigned i = 0; i < itemCount; ++i) + for (unsigned i = 0; i < min(itemCount, 256); ++i) // process 256 transactions at most. TODO: much better solution. { auto h = sha3(_r[i].data()); _peer->m_knownTransactions.insert(h); diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 86e2a070d..87d51969a 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -37,6 +37,18 @@ using namespace dev; using namespace dev::eth; using namespace p2p; +string toString(Asking _a) +{ + switch (_a) + { + case Asking::Blocks: return "Blocks"; + case Asking::Hashes: return "Hashes"; + case Asking::Nothing: return "Nothing"; + case Asking::State: return "State"; + } + return "?"; +} + EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap): Capability(_s, _h, _i), m_sub(host()->downloadMan()), @@ -49,6 +61,11 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap EthereumPeer::~EthereumPeer() { + if (m_asking != Asking::Nothing) + { + cnote << "Peer aborting while being asked for " << ::toString(m_asking); + setRude(); + } abortSync(); } @@ -65,7 +82,9 @@ unsigned EthereumPeer::askOverride() const void EthereumPeer::setRude() { + auto old = askOverride(); repMan().setData(*session(), name(), rlp(askOverride() / 2 + 1)); + cnote << "Rude behaviour; askOverride now" << askOverride() << ", was" << old; repMan().noteRude(*session(), name()); session()->addNote("manners", "RUDE"); } @@ -84,18 +103,6 @@ EthereumHost* EthereumPeer::host() const * Possible asking/syncing states for two peers: */ -string toString(Asking _a) -{ - switch (_a) - { - case Asking::Blocks: return "Blocks"; - case Asking::Hashes: return "Hashes"; - case Asking::Nothing: return "Nothing"; - case Asking::State: return "State"; - } - return "?"; -} - void EthereumPeer::setIdle() { setAsking(Asking::Nothing); From 955a1d1bb17960a62edc3462f3c6da9c10168e9d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 19 Jun 2015 14:57:25 +0800 Subject: [PATCH 103/103] Version bump. --- libdevcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 22ea584c1..17ccae6b1 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -28,7 +28,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.26"; +char const* Version = "0.9.27"; const u256 UndefinedU256 = ~(u256)0;