From d865309d5593fe1f9b64befb8a8fa520ace2c42b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 27 Jun 2014 21:39:46 +0200 Subject: [PATCH 1/4] Latest tests-related refactoring & improvments. --- test/trie.cpp | 5 ++- test/vm.cpp | 104 +++++++++++++++++++++++----------------------- test/vmtests.json | 31 +++++--------- 3 files changed, 65 insertions(+), 75 deletions(-) diff --git a/test/trie.cpp b/test/trie.cpp index defa87879..12d2c2e3f 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(trie_tests) cnote << "Testing Trie..."; js::mValue v; string s = asString(contents("../../../tests/trietest.json")); - BOOST_REQUIRE_MESSAGE( s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?"); + 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); for (auto& i: v.get_obj()) { @@ -60,6 +60,7 @@ BOOST_AUTO_TEST_CASE(trie_tests) vector> ss; for (auto& i: o["in"].get_obj()) ss.push_back(make_pair(i.first, i.second.get_str())); + cnote << ss; for (unsigned j = 0; j < eth::test::fac((unsigned)ss.size()); ++j) { next_permutation(ss.begin(), ss.end()); @@ -74,7 +75,7 @@ BOOST_AUTO_TEST_CASE(trie_tests) BOOST_REQUIRE(t.check(true)); } BOOST_REQUIRE(!o["root"].is_null()); - BOOST_CHECK(o["root"].get_str() == toHex(t.root().asArray()) ); + BOOST_CHECK_EQUAL(o["root"].get_str(), toHex(t.root().asArray())); } } } diff --git a/test/vm.cpp b/test/vm.cpp index 0d2d2d1e4..f59704178 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -128,48 +128,6 @@ public: set(myAddress, _myBalance, _myNonce, _storage, get<3>(addresses[myAddress])); } - mObject exportEnv() - { - mObject ret; - ret["previousHash"] = toString(previousBlock.hash); - push(ret, "currentDifficulty", currentBlock.difficulty); - push(ret, "currentTimestamp", currentBlock.timestamp); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); - push(ret, "currentNumber", currentBlock.number); - push(ret, "currentGasLimit", currentBlock.gasLimit); - - mArray c; - for (auto const& i: code) - push(c, i); - ret["code"] = c; - return ret; - } - - void importEnv(mObject& _o) - { - BOOST_REQUIRE(_o.count("previousHash") > 0); - BOOST_REQUIRE(_o.count("currentGasLimit") > 0); - BOOST_REQUIRE(_o.count("currentDifficulty") > 0); - BOOST_REQUIRE(_o.count("currentTimestamp") > 0); - BOOST_REQUIRE(_o.count("currentCoinbase") > 0); - BOOST_REQUIRE(_o.count("currentNumber") > 0); - - previousBlock.hash = h256(_o["previousHash"].get_str()); - currentBlock.number = toInt(_o["currentNumber"]); - currentBlock.gasLimit = toInt(_o["currentGasLimit"]); - currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); - - thisTxCode.clear(); - if (_o["code"].type() == str_type) - thisTxCode = compileLLL(_o["code"].get_str()); - else - for (auto const& j: _o["code"].get_array()) - thisTxCode.push_back(toByte(j)); - code = &thisTxCode; - } - static u256 toInt(mValue const& _v) { switch (_v.type()) @@ -212,6 +170,35 @@ public: a.push_back(toString(_v)); } + mObject exportEnv() + { + mObject ret; + ret["previousHash"] = toString(previousBlock.hash); + push(ret, "currentDifficulty", currentBlock.difficulty); + push(ret, "currentTimestamp", currentBlock.timestamp); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + push(ret, "currentNumber", currentBlock.number); + push(ret, "currentGasLimit", currentBlock.gasLimit); + return ret; + } + + void importEnv(mObject& _o) + { + BOOST_REQUIRE(_o.count("previousHash") > 0); + BOOST_REQUIRE(_o.count("currentGasLimit") > 0); + BOOST_REQUIRE(_o.count("currentDifficulty") > 0); + BOOST_REQUIRE(_o.count("currentTimestamp") > 0); + BOOST_REQUIRE(_o.count("currentCoinbase") > 0); + BOOST_REQUIRE(_o.count("currentNumber") > 0); + + previousBlock.hash = h256(_o["previousHash"].get_str()); + currentBlock.number = toInt(_o["currentNumber"]); + currentBlock.gasLimit = toInt(_o["currentGasLimit"]); + currentBlock.difficulty = toInt(_o["currentDifficulty"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + } + mObject exportState() { mObject ret; @@ -301,6 +288,10 @@ public: for (auto const& i: data) push(d, i); ret["data"] = d; + mArray c; + for (auto const& i: code) + push(c, i); + ret["code"] = c; return ret; } @@ -321,6 +312,16 @@ public: gasPrice = toInt(_o["gasPrice"]); gas = toInt(_o["gas"]); + thisTxCode.clear(); + code = &thisTxCode; + if (_o["code"].type() == str_type) + thisTxCode = compileLLL(_o["code"].get_str()); + else if (_o["code"].type() == array_type) + for (auto const& j: _o["code"].get_array()) + thisTxCode.push_back(toByte(j)); + else + code.reset(); + thisTxData.clear(); if (_o["data"].type() == str_type) thisTxData = fromHex(_o["data"].get_str()); @@ -396,15 +397,15 @@ void doTests(json_spirit::mValue& v, bool _fillin) if (_fillin) o["pre"] = mValue(fev.exportState()); - bytes output; - for (auto i: o["exec"].get_array()) - { - fev.importExec(i.get_obj()); - vm.reset(fev.gas); - output = vm.go(fev).toBytes(); - } + fev.importExec(o["exec"].get_obj()); + if (!fev.code) + fev.code = &get<3>(fev.addresses.at(fev.myAddress)); + vm.reset(fev.gas); + bytes output = vm.go(fev).toBytes(); + if (_fillin) { + o["exec"] = mValue(fev.exportExec()); o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); mArray df; @@ -479,12 +480,11 @@ BOOST_AUTO_TEST_CASE(vm_tests) eth::test::doTests(v, true); writeFile("../../../tests/vmtests.json", asBytes(json_spirit::write_string(v, true))); } - catch( std::exception& e) + catch (std::exception const& e) { BOOST_ERROR("Failed VM Test with Exception: " << e.what()); } - try { cnote << "Testing VM..."; @@ -494,7 +494,7 @@ BOOST_AUTO_TEST_CASE(vm_tests) json_spirit::read_string(s, v); eth::test::doTests(v, false); } - catch( std::exception& e) + catch (std::exception const& e) { BOOST_ERROR("Failed VM Test with Exception: " << e.what()); } diff --git a/test/vmtests.json b/test/vmtests.json index a05975c94..6dce8bff7 100644 --- a/test/vmtests.json +++ b/test/vmtests.json @@ -6,8 +6,7 @@ "currentGasLimit" : "1000000", "currentDifficulty" : "256", "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "code" : "(suicide (caller))" + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { @@ -17,8 +16,7 @@ "storage": {} } }, - "exec" : [ - { + "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", @@ -27,7 +25,6 @@ "gasPrice" : "100000000000000", "gas" : "10000" } - ] }, "arith": { @@ -37,8 +34,7 @@ "currentGasLimit" : "1000000", "currentDifficulty" : "256", "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "code" : "{ (call (- (gas) 200) (caller) (+ 2 2 (* 4 4 4) (/ 2 2) (% 3 2) (- 8 2 2)) 0 0 0 0) }" + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { @@ -48,9 +44,8 @@ "storage": {} } }, - "exec" : [ - { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", "value" : "1000000000000000000", @@ -58,7 +53,6 @@ "gasPrice" : "100000000000000", "gas" : "10000" } - ] }, "boolean": { @@ -68,8 +62,7 @@ "currentGasLimit" : "1000000", "currentDifficulty" : "256", "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "code" : "(seq (when (and 1 1) (call (- (gas) 200) (caller) 2 0 0 0 0)) (when (and 1 0) (call (- (gas) 200) (caller) 3 0 0 0 0)) (when (and 0 1) (call (- (gas) 200) (caller) 4 0 0 0 0)) (when (and 0 0) (call (- (gas) 200) (caller) 5 0 0 0 0)) (when (or 1 1) (call (- (gas) 200) (caller) 12 0 0 0 0)) (when (or 1 0) (call (- (gas) 200) (caller) 13 0 0 0 0)) (when (or 0 1) (call (- (gas) 200) (caller) 14 0 0 0 0)) (when (or 0 0) (call (- (gas) 200) (caller) 15 0 0 0 0)) )" + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { @@ -78,9 +71,8 @@ "code" : "(seq (when (and 1 1) (call (- (gas) 200) (caller) 2 0 0 0 0)) (when (and 1 0) (call (- (gas) 200) (caller) 3 0 0 0 0)) (when (and 0 1) (call (- (gas) 200) (caller) 4 0 0 0 0)) (when (and 0 0) (call (- (gas) 200) (caller) 5 0 0 0 0)) (when (or 1 1) (call (- (gas) 200) (caller) 12 0 0 0 0)) (when (or 1 0) (call (- (gas) 200) (caller) 13 0 0 0 0)) (when (or 0 1) (call (- (gas) 200) (caller) 14 0 0 0 0)) (when (or 0 0) (call (- (gas) 200) (caller) 15 0 0 0 0)) )", "storage": {} } - }, - "exec" : [ - { + }, + "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", @@ -89,7 +81,6 @@ "gasPrice" : "100000000000000", "gas" : "10000" } - ] }, "mktx": { @@ -99,8 +90,7 @@ "currentGasLimit" : "1000000", "currentDifficulty" : "256", "currentTimestamp" : 1, - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "code" : "(call (- (gas) 200) (caller) 500000000000000000 0 0 0 0)" + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { @@ -110,7 +100,7 @@ "storage": {} } }, - "exec" : [ + "exec" : { "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", @@ -120,6 +110,5 @@ "gas" : "10000", "data" : "" } - ] } } From fcb5b82e5f99dcc2dc953caa1871f783fe64f9c4 Mon Sep 17 00:00:00 2001 From: Vincent Gariepy Date: Fri, 27 Jun 2014 15:43:22 -0400 Subject: [PATCH 2/4] neth: show mining speed --- neth/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/neth/main.cpp b/neth/main.cpp index 929f3cbc5..d82ca4625 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -951,7 +951,12 @@ int main(int argc, char** argv) // Mining flag if (c.isMining()) + { mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON"); + eth::MineProgress p = c.miningProgress(); + auto speed = boost::format("%2% kH/s @ %1%s") % (p.ms / 1000) % (p.ms ? p.hashes / p.ms : 0); + mvwprintw(consolewin, qheight - 2, width / 4 - speed.str().length() - 2, speed.str().c_str()); + } else mvwprintw(consolewin, qheight - 1, width / 4 - 12, "Mining OFF"); From 87b25a3804af797a584a31c8b16b59857b7db7a7 Mon Sep 17 00:00:00 2001 From: Vincent Gariepy Date: Fri, 27 Jun 2014 15:44:58 -0400 Subject: [PATCH 3/4] save url in aleth --- alethzero/MainWin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index d45599cd3..754481029 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -360,6 +360,7 @@ void Main::writeSettings() s.setValue("clientName", ui->clientName->text()); s.setValue("idealPeers", ui->idealPeers->value()); s.setValue("port", ui->port->value()); + s.setValue("url", ui->urlEdit->text()); if (m_client->peerServer()) { From 25183afd7c14fa40b67f46713c42e3c3252f6517 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 27 Jun 2014 23:47:24 +0200 Subject: [PATCH 4/4] Project refactor. Introduce the Serpent library. --- CMakeLists.txt | 18 +- alethzero/MainWin.h | 2 +- eth/CommonJS.h | 8 +- eth/EthStubServer.cpp | 2 +- eth/main.cpp | 4 +- exp/main.cpp | 6 +- libethcore/BlockInfo.cpp | 10 +- libethcore/BlockInfo.h | 4 +- libethcore/CMakeLists.txt | 2 +- libethcore/CommonEth.cpp | 1 + libethcore/CommonEth.h | 4 +- {libethsupport => libethcore}/CryptoHeaders.h | 0 libethcore/Dagger.cpp | 8 +- libethcore/Dagger.h | 1 + libethcore/Exceptions.h | 2 +- {libethsupport => libethcore}/FileSystem.cpp | 4 +- {libethsupport => libethcore}/FileSystem.h | 0 {libethsupport => libethcore}/MemoryDB.cpp | 2 +- {libethsupport => libethcore}/MemoryDB.h | 8 +- {libethsupport => libethcore}/OverlayDB.cpp | 2 +- {libethsupport => libethcore}/OverlayDB.h | 4 +- .../FixedHash.cpp => libethcore/SHA3.cpp | 5 +- libethcore/SHA3.h | 61 +++ {libethsupport => libethcore}/TrieCommon.cpp | 0 {libethsupport => libethcore}/TrieCommon.h | 4 +- {libethsupport => libethcore}/TrieDB.cpp | 5 +- {libethsupport => libethcore}/TrieDB.h | 5 +- {libethsupport => libethcore}/UPnP.cpp | 10 +- {libethsupport => libethcore}/UPnP.h | 0 libethential/CMakeLists.txt | 51 ++ {libethsupport => libethential}/Common.cpp | 2 +- {libethsupport => libethential}/Common.h | 0 .../CommonData.cpp | 0 {libethsupport => libethential}/CommonData.h | 0 {libethsupport => libethential}/CommonIO.cpp | 0 {libethsupport => libethential}/CommonIO.h | 0 {libethsupport => libethential}/Exceptions.h | 0 libethential/FixedHash.cpp | 25 + {libethsupport => libethential}/FixedHash.h | 28 -- {libethsupport => libethential}/Log.cpp | 0 {libethsupport => libethential}/Log.h | 0 {libethsupport => libethential}/RLP.cpp | 0 {libethsupport => libethential}/RLP.h | 8 +- {libethsupport => libethential}/vector_ref.h | 2 +- libethereum/AddressState.h | 5 +- libethereum/BlockChain.cpp | 6 +- libethereum/BlockChain.h | 2 +- libethereum/CMakeLists.txt | 1 - libethereum/Client.cpp | 2 +- libethereum/Client.h | 2 +- libethereum/Defaults.cpp | 2 +- libethereum/Defaults.h | 2 +- libethereum/Executive.h | 2 +- libethereum/PeerNetwork.h | 4 +- libethereum/PeerServer.cpp | 4 +- libethereum/PeerSession.cpp | 2 +- libethereum/PeerSession.h | 2 +- libethereum/State.cpp | 2 +- libethereum/State.h | 6 +- libethereum/Transaction.cpp | 4 +- libethereum/Transaction.h | 3 +- libethereum/TransactionQueue.cpp | 2 +- libethereum/TransactionQueue.h | 2 +- libevm/CMakeLists.txt | 3 +- libevm/ExtVMFace.h | 2 +- libevm/FeeStructure.h | 2 +- libevm/VM.h | 5 +- libevmface/CMakeLists.txt | 51 ++ {libethcore => libevmface}/Instruction.cpp | 2 +- {libethcore => libevmface}/Instruction.h | 4 +- liblll/Assembly.cpp | 2 +- liblll/Assembly.h | 5 +- liblll/CMakeLists.txt | 11 +- liblll/CodeFragment.cpp | 4 +- liblll/CodeFragment.h | 4 +- liblll/Compiler.h | 2 +- liblll/Parser.h | 2 +- libqethereum/QEthereum.cpp | 4 +- libqethereum/QEthereum.h | 2 +- {libethsupport => libserpent}/CMakeLists.txt | 10 +- libserpent/bignum.cpp | 98 ++++ libserpent/bignum.h | 30 ++ libserpent/compiler.cpp | 407 +++++++++++++++ libserpent/compiler.h | 43 ++ libserpent/example.cpp | 11 + libserpent/funcs.cpp | 23 + libserpent/funcs.h | 29 ++ libserpent/lllparser.cpp | 70 +++ libserpent/lllparser.h | 13 + libserpent/opcodes.h | 91 ++++ libserpent/parser.cpp | 387 +++++++++++++++ libserpent/parser.h | 13 + libserpent/rewriter.cpp | 466 ++++++++++++++++++ libserpent/rewriter.h | 13 + libserpent/tokenize.cpp | 111 +++++ libserpent/tokenize.h | 14 + libserpent/util.cpp | 256 ++++++++++ libserpent/util.h | 106 ++++ lllc/CMakeLists.txt | 4 - lllc/main.cpp | 6 +- neth/main.cpp | 4 +- test/MemTrie.cpp | 3 +- test/MemTrie.h | 4 +- test/TrieHash.cpp | 3 +- test/TrieHash.h | 4 +- test/crypto.cpp | 6 +- test/dagger.cpp | 2 +- test/hexPrefix.cpp | 4 +- test/main.cpp | 4 +- test/rlp.cpp | 6 +- test/trie.cpp | 2 +- test/vm.cpp | 8 +- walleth/MainWin.cpp | 4 +- 113 files changed, 2535 insertions(+), 178 deletions(-) rename {libethsupport => libethcore}/CryptoHeaders.h (100%) rename {libethsupport => libethcore}/FileSystem.cpp (96%) rename {libethsupport => libethcore}/FileSystem.h (100%) rename {libethsupport => libethcore}/MemoryDB.cpp (98%) rename {libethsupport => libethcore}/MemoryDB.h (93%) rename {libethsupport => libethcore}/OverlayDB.cpp (98%) rename {libethsupport => libethcore}/OverlayDB.h (95%) rename libethsupport/FixedHash.cpp => libethcore/SHA3.cpp (97%) create mode 100644 libethcore/SHA3.h rename {libethsupport => libethcore}/TrieCommon.cpp (100%) rename {libethsupport => libethcore}/TrieCommon.h (98%) rename {libethsupport => libethcore}/TrieDB.cpp (93%) rename {libethsupport => libethcore}/TrieDB.h (99%) rename {libethsupport => libethcore}/UPnP.cpp (97%) rename {libethsupport => libethcore}/UPnP.h (100%) create mode 100644 libethential/CMakeLists.txt rename {libethsupport => libethential}/Common.cpp (95%) rename {libethsupport => libethential}/Common.h (100%) rename {libethsupport => libethential}/CommonData.cpp (100%) rename {libethsupport => libethential}/CommonData.h (100%) rename {libethsupport => libethential}/CommonIO.cpp (100%) rename {libethsupport => libethential}/CommonIO.h (100%) rename {libethsupport => libethential}/Exceptions.h (100%) create mode 100644 libethential/FixedHash.cpp rename {libethsupport => libethential}/FixedHash.h (84%) rename {libethsupport => libethential}/Log.cpp (100%) rename {libethsupport => libethential}/Log.h (100%) rename {libethsupport => libethential}/RLP.cpp (100%) rename {libethsupport => libethential}/RLP.h (98%) rename {libethsupport => libethential}/vector_ref.h (99%) create mode 100644 libevmface/CMakeLists.txt rename {libethcore => libevmface}/Instruction.cpp (99%) rename {libethcore => libevmface}/Instruction.h (97%) rename {libethsupport => libserpent}/CMakeLists.txt (90%) create mode 100644 libserpent/bignum.cpp create mode 100644 libserpent/bignum.h create mode 100644 libserpent/compiler.cpp create mode 100644 libserpent/compiler.h create mode 100644 libserpent/example.cpp create mode 100644 libserpent/funcs.cpp create mode 100644 libserpent/funcs.h create mode 100644 libserpent/lllparser.cpp create mode 100644 libserpent/lllparser.h create mode 100644 libserpent/opcodes.h create mode 100644 libserpent/parser.cpp create mode 100644 libserpent/parser.h create mode 100644 libserpent/rewriter.cpp create mode 100644 libserpent/rewriter.h create mode 100644 libserpent/tokenize.cpp create mode 100644 libserpent/tokenize.h create mode 100644 libserpent/util.cpp create mode 100644 libserpent/util.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 84c447908..a2d4a48ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,11 +5,8 @@ set(CMAKE_AUTOMOC ON) cmake_policy(SET CMP0015 NEW) -# Default HEADLESS to 0. set(HEADLESS CACHE BOOL 0) -#if ("x${HEADLESS}" STREQUAL "x") -# set(HEADLESS 0) -#endif () +set(LANGUAGES CACHE BOOL 0) if ("x${PARANOIA}" STREQUAL "x") if ("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") @@ -35,6 +32,10 @@ if (VMTRACE) add_definitions(-DETH_VMTRACE) endif () +if (LANGUAGES) + add_definitions(-DETH_LANGUAGES) +endif () + # Default TARGET_PLATFORM to "linux". set(TARGET_PLATFORM CACHE STRING "linux") if ("x${TARGET_PLATFORM}" STREQUAL "x") @@ -271,16 +272,18 @@ endif() # Generate header file containing useful build information add_custom_target(BuildInfo.h ALL COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BUILD_TYPE} ${ETH_BUILD_PLATFORM}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") link_directories(/usr/local/lib) include_directories(/usr/local/include) endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") +add_subdirectory(libethential) +add_subdirectory(libevmface) +add_subdirectory(liblll) +add_subdirectory(libserpent) +if (NOT LANGUAGES) add_subdirectory(secp256k1) -add_subdirectory(libethsupport) add_subdirectory(libethcore) -add_subdirectory(liblll) add_subdirectory(libevm) add_subdirectory(libethereum) add_subdirectory(test) @@ -298,6 +301,7 @@ if (NOT HEADLESS) add_subdirectory(alethzero) add_subdirectory(walleth) endif () +endif () enable_testing() add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth) diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index c372a7b5a..8d19e4118 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/eth/CommonJS.h b/eth/CommonJS.h index c62be22db..57f2db39f 100644 --- a/eth/CommonJS.h +++ b/eth/CommonJS.h @@ -23,10 +23,10 @@ #pragma once #include -#include -#include -#include -#include +#include +#include +#include +#include #include namespace eth diff --git a/eth/EthStubServer.cpp b/eth/EthStubServer.cpp index 922328de9..c0ad7ee5d 100644 --- a/eth/EthStubServer.cpp +++ b/eth/EthStubServer.cpp @@ -22,7 +22,7 @@ #if ETH_JSONRPC #include "EthStubServer.h" -#include +#include #include #include #include "CommonJS.h" diff --git a/eth/main.cpp b/eth/main.cpp index 7410fbe6d..ba12ff8ef 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -26,8 +26,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/exp/main.cpp b/exp/main.cpp index 31f4ea4b4..6a5e5557f 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -20,9 +20,9 @@ * Ethereum client. */ -#include -#include -#include +#include +#include +#include #include "BuildInfo.h" using namespace std; using namespace eth; diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index e441b749b..434971c28 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -19,9 +19,11 @@ * @date 2014 */ -#include -#include -#include +#if !ETH_LANGUAGES + +#include +#include +#include #include "Dagger.h" #include "Exceptions.h" #include "BlockInfo.h" @@ -189,3 +191,5 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const throw InvalidNumber(); } } + +#endif diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 209f4629e..098433af3 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -21,8 +21,8 @@ #pragma once -#include -#include +#include +#include #include "CommonEth.h" namespace eth diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index c1f70a8b0..d2ecdf0b0 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -21,7 +21,7 @@ include_directories(..) include_directories(${MINIUPNPC_ID}) include_directories(${LEVELDB_ID}) -target_link_libraries(${EXECUTABLE} ethsupport) +target_link_libraries(${EXECUTABLE} ethential) target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index c5ea5ff99..e4f629f8c 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -22,6 +22,7 @@ #include "CommonEth.h" #include #include +#include #include "Exceptions.h" using namespace std; using namespace eth; diff --git a/libethcore/CommonEth.h b/libethcore/CommonEth.h index bfef42831..6b28261f1 100644 --- a/libethcore/CommonEth.h +++ b/libethcore/CommonEth.h @@ -23,8 +23,8 @@ #pragma once -#include -#include +#include +#include namespace eth { diff --git a/libethsupport/CryptoHeaders.h b/libethcore/CryptoHeaders.h similarity index 100% rename from libethsupport/CryptoHeaders.h rename to libethcore/CryptoHeaders.h diff --git a/libethcore/Dagger.cpp b/libethcore/Dagger.cpp index 3df1d7c85..2b759fb7c 100644 --- a/libethcore/Dagger.cpp +++ b/libethcore/Dagger.cpp @@ -19,12 +19,14 @@ * @date 2014 */ +#if !ETH_LANGUAGES + #include #include #include #include -#include -#include +#include +#include #include "Dagger.h" using namespace std; using namespace std::chrono; @@ -179,3 +181,5 @@ h256 Dagger::eval(h256 const& _root, u256 const& _nonce) #endif } + +#endif diff --git a/libethcore/Dagger.h b/libethcore/Dagger.h index 0db8f6aca..1adb59a9c 100644 --- a/libethcore/Dagger.h +++ b/libethcore/Dagger.h @@ -23,6 +23,7 @@ #pragma once +#include #include "CommonEth.h" #define FAKE_DAGGER 1 diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index e379c54d0..127a84450 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace eth { diff --git a/libethsupport/FileSystem.cpp b/libethcore/FileSystem.cpp similarity index 96% rename from libethsupport/FileSystem.cpp rename to libethcore/FileSystem.cpp index 8c55937ed..6d7044753 100644 --- a/libethsupport/FileSystem.cpp +++ b/libethcore/FileSystem.cpp @@ -22,8 +22,8 @@ */ #include "FileSystem.h" -#include "Common.h" -#include "Log.h" +#include +#include #ifdef _WIN32 #include diff --git a/libethsupport/FileSystem.h b/libethcore/FileSystem.h similarity index 100% rename from libethsupport/FileSystem.h rename to libethcore/FileSystem.h diff --git a/libethsupport/MemoryDB.cpp b/libethcore/MemoryDB.cpp similarity index 98% rename from libethsupport/MemoryDB.cpp rename to libethcore/MemoryDB.cpp index aa4621307..8755266c3 100644 --- a/libethsupport/MemoryDB.cpp +++ b/libethcore/MemoryDB.cpp @@ -19,7 +19,7 @@ * @date 2014 */ -#include "Common.h" +#include #include "MemoryDB.h" using namespace std; using namespace eth; diff --git a/libethsupport/MemoryDB.h b/libethcore/MemoryDB.h similarity index 93% rename from libethsupport/MemoryDB.h rename to libethcore/MemoryDB.h index c5627b4d7..33cd71fcd 100644 --- a/libethsupport/MemoryDB.h +++ b/libethcore/MemoryDB.h @@ -22,10 +22,10 @@ #pragma once #include -#include "Common.h" -#include "FixedHash.h" -#include "RLP.h" -#include "Log.h" +#include +#include +#include +#include namespace eth { diff --git a/libethsupport/OverlayDB.cpp b/libethcore/OverlayDB.cpp similarity index 98% rename from libethsupport/OverlayDB.cpp rename to libethcore/OverlayDB.cpp index 04e576ae1..a8941e9ef 100644 --- a/libethsupport/OverlayDB.cpp +++ b/libethcore/OverlayDB.cpp @@ -19,7 +19,7 @@ * @date 2014 */ -#include "Common.h" +#include #include "OverlayDB.h" using namespace std; using namespace eth; diff --git a/libethsupport/OverlayDB.h b/libethcore/OverlayDB.h similarity index 95% rename from libethsupport/OverlayDB.h rename to libethcore/OverlayDB.h index 9a5653360..e2a5aba1a 100644 --- a/libethsupport/OverlayDB.h +++ b/libethcore/OverlayDB.h @@ -22,9 +22,9 @@ #pragma once #include -#include "Common.h" +#include +#include #include "MemoryDB.h" -#include "Log.h" namespace ldb = leveldb; namespace eth diff --git a/libethsupport/FixedHash.cpp b/libethcore/SHA3.cpp similarity index 97% rename from libethsupport/FixedHash.cpp rename to libethcore/SHA3.cpp index bc23d22c8..90e85f4ef 100644 --- a/libethsupport/FixedHash.cpp +++ b/libethcore/SHA3.cpp @@ -14,12 +14,12 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file FixedHash.cpp +/** @file SHA3.cpp * @author Gav Wood * @date 2014 */ -#include "FixedHash.h" +#include "SHA3.h" #include "CryptoHeaders.h" using namespace std; @@ -65,3 +65,4 @@ h256 eth::sha3(bytesConstRef _input) sha3(_input, bytesRef(&ret[0], 32)); return ret; } + diff --git a/libethcore/SHA3.h b/libethcore/SHA3.h new file mode 100644 index 000000000..5972c0e47 --- /dev/null +++ b/libethcore/SHA3.h @@ -0,0 +1,61 @@ +/* + 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 FixedHash.h + * @author Gav Wood + * @date 2014 + * + * The FixedHash fixed-size "hash" container type. + */ + +#pragma once + +#include +#include +#include + +namespace eth +{ + +// SHA-3 convenience routines. + +/// Calculate SHA3-256 hash of the given input and load it into the given output. +void sha3(bytesConstRef _input, bytesRef _output); + +/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. +std::string sha3(std::string const& _input, bool _isNibbles); + +/// Calculate SHA3-256 hash of the given input, returning as a byte array. +bytes sha3Bytes(bytesConstRef _input); + +/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array. +inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); } + +/// Calculate SHA3-256 hash of the given input, returning as a byte array. +inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); } + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +h256 sha3(bytesConstRef _input); + +/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. +inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); } + +/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. +inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } + +extern h256 EmptySHA3; + +} diff --git a/libethsupport/TrieCommon.cpp b/libethcore/TrieCommon.cpp similarity index 100% rename from libethsupport/TrieCommon.cpp rename to libethcore/TrieCommon.cpp diff --git a/libethsupport/TrieCommon.h b/libethcore/TrieCommon.h similarity index 98% rename from libethsupport/TrieCommon.h rename to libethcore/TrieCommon.h index 99176ef8d..c748fd8d0 100644 --- a/libethsupport/TrieCommon.h +++ b/libethcore/TrieCommon.h @@ -21,8 +21,8 @@ #pragma once -#include "Common.h" -#include "RLP.h" +#include +#include namespace eth { diff --git a/libethsupport/TrieDB.cpp b/libethcore/TrieDB.cpp similarity index 93% rename from libethsupport/TrieDB.cpp rename to libethcore/TrieDB.cpp index 7160fe5b5..c0562889f 100644 --- a/libethsupport/TrieDB.cpp +++ b/libethcore/TrieDB.cpp @@ -19,7 +19,7 @@ * @date 2014 */ -#include "Common.h" +#include #include "TrieDB.h" using namespace std; using namespace eth; @@ -27,6 +27,9 @@ using namespace eth; namespace eth { +#if !ETH_LANGUAGES + const h256 c_shaNull = sha3(rlp("")); +#endif } diff --git a/libethsupport/TrieDB.h b/libethcore/TrieDB.h similarity index 99% rename from libethsupport/TrieDB.h rename to libethcore/TrieDB.h index a9dba9d1c..023a0dc1d 100644 --- a/libethsupport/TrieDB.h +++ b/libethcore/TrieDB.h @@ -23,10 +23,11 @@ #include #include -#include "Common.h" +#include +#include +#include #include "MemoryDB.h" #include "OverlayDB.h" -#include "Log.h" #include "TrieCommon.h" namespace ldb = leveldb; diff --git a/libethsupport/UPnP.cpp b/libethcore/UPnP.cpp similarity index 97% rename from libethsupport/UPnP.cpp rename to libethcore/UPnP.cpp index 292444fc6..409eca430 100644 --- a/libethsupport/UPnP.cpp +++ b/libethcore/UPnP.cpp @@ -20,14 +20,16 @@ * @date 2014 */ +#if !ETH_LANGUAGES + #include #include #include #include #include -#include "Exceptions.h" -#include "Common.h" -#include "Log.h" +#include +#include +#include #include "UPnP.h" using namespace std; using namespace eth; @@ -167,3 +169,5 @@ void UPnP::removeRedirect(int port) UPNP_DeletePortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, "TCP", NULL); m_reg.erase(port); } + +#endif diff --git a/libethsupport/UPnP.h b/libethcore/UPnP.h similarity index 100% rename from libethsupport/UPnP.h rename to libethcore/UPnP.h diff --git a/libethential/CMakeLists.txt b/libethential/CMakeLists.txt new file mode 100644 index 000000000..5ac121018 --- /dev/null +++ b/libethential/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_policy(SET CMP0015 NEW) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") + +aux_source_directory(. SRC_LIST) + +set(EXECUTABLE ethential) + +if(APPLE) + # set(CMAKE_INSTALL_PREFIX ../lib) + add_library(${EXECUTABLE} SHARED ${SRC_LIST}) +else() + add_library(${EXECUTABLE} ${SRC_LIST}) +endif() +file(GLOB HEADERS "*.h") + +include_directories(..) + +target_link_libraries(${EXECUTABLE} ethential) +target_link_libraries(${EXECUTABLE} gmp) + + +if(${TARGET_PLATFORM} STREQUAL "w64") + include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) + target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) + target_link_libraries(${EXECUTABLE} iphlpapi) + target_link_libraries(${EXECUTABLE} ws2_32) + target_link_libraries(${EXECUTABLE} mswsock) + target_link_libraries(${EXECUTABLE} shlwapi) +elseif (APPLE) + # Latest mavericks boost libraries only come with -mt + find_package(Threads REQUIRED) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +elseif (UNIX) + target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +else () + target_link_libraries(${EXECUTABLE} boost_thread) + find_package(Threads REQUIRED) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +endif () + +if (UNIX) + FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework locale) +endif() + +message("Installation path: ${CMAKE_INSTALL_PREFIX}") + +install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/libethsupport/Common.cpp b/libethential/Common.cpp similarity index 95% rename from libethsupport/Common.cpp rename to libethential/Common.cpp index c47a9fbe9..fc4708f23 100644 --- a/libethsupport/Common.cpp +++ b/libethential/Common.cpp @@ -27,6 +27,6 @@ using namespace eth; namespace eth { -char const* EthVersion = "0.5.11"; +char const* EthVersion = "0.5.12"; } diff --git a/libethsupport/Common.h b/libethential/Common.h similarity index 100% rename from libethsupport/Common.h rename to libethential/Common.h diff --git a/libethsupport/CommonData.cpp b/libethential/CommonData.cpp similarity index 100% rename from libethsupport/CommonData.cpp rename to libethential/CommonData.cpp diff --git a/libethsupport/CommonData.h b/libethential/CommonData.h similarity index 100% rename from libethsupport/CommonData.h rename to libethential/CommonData.h diff --git a/libethsupport/CommonIO.cpp b/libethential/CommonIO.cpp similarity index 100% rename from libethsupport/CommonIO.cpp rename to libethential/CommonIO.cpp diff --git a/libethsupport/CommonIO.h b/libethential/CommonIO.h similarity index 100% rename from libethsupport/CommonIO.h rename to libethential/CommonIO.h diff --git a/libethsupport/Exceptions.h b/libethential/Exceptions.h similarity index 100% rename from libethsupport/Exceptions.h rename to libethential/Exceptions.h diff --git a/libethential/FixedHash.cpp b/libethential/FixedHash.cpp new file mode 100644 index 000000000..9d16cacb2 --- /dev/null +++ b/libethential/FixedHash.cpp @@ -0,0 +1,25 @@ +/* + 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 FixedHash.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "FixedHash.h" + +using namespace std; +using namespace eth; diff --git a/libethsupport/FixedHash.h b/libethential/FixedHash.h similarity index 84% rename from libethsupport/FixedHash.h rename to libethential/FixedHash.h index 728e36e50..240cea603 100644 --- a/libethsupport/FixedHash.h +++ b/libethential/FixedHash.h @@ -197,34 +197,6 @@ inline h160 left160(h256 const& _t) return ret; } -// SHA-3 convenience routines. - -/// Calculate SHA3-256 hash of the given input and load it into the given output. -void sha3(bytesConstRef _input, bytesRef _output); - -/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. -std::string sha3(std::string const& _input, bool _isNibbles); - -/// Calculate SHA3-256 hash of the given input, returning as a byte array. -bytes sha3Bytes(bytesConstRef _input); - -/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array. -inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); } - -/// Calculate SHA3-256 hash of the given input, returning as a byte array. -inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); } - -/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. -h256 sha3(bytesConstRef _input); - -/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. -inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); } - -/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. -inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } - -extern h256 EmptySHA3; - } namespace std diff --git a/libethsupport/Log.cpp b/libethential/Log.cpp similarity index 100% rename from libethsupport/Log.cpp rename to libethential/Log.cpp diff --git a/libethsupport/Log.h b/libethential/Log.h similarity index 100% rename from libethsupport/Log.h rename to libethential/Log.h diff --git a/libethsupport/RLP.cpp b/libethential/RLP.cpp similarity index 100% rename from libethsupport/RLP.cpp rename to libethential/RLP.cpp diff --git a/libethsupport/RLP.h b/libethential/RLP.h similarity index 98% rename from libethsupport/RLP.h rename to libethential/RLP.h index 769ef770c..a3f42a783 100644 --- a/libethsupport/RLP.h +++ b/libethential/RLP.h @@ -28,10 +28,10 @@ #include #include #include -#include "vector_ref.h" -#include "Common.h" -#include "Exceptions.h" -#include "FixedHash.h" +#include +#include +#include +#include namespace eth { diff --git a/libethsupport/vector_ref.h b/libethential/vector_ref.h similarity index 99% rename from libethsupport/vector_ref.h rename to libethential/vector_ref.h index 66f479f8c..4bde3f582 100644 --- a/libethsupport/vector_ref.h +++ b/libethential/vector_ref.h @@ -54,7 +54,7 @@ public: _T const& operator[](size_t _i) const { assert(m_data); assert(_i < m_count); return m_data[_i]; } bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; } - bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(); } + bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); } operator leveldb::Slice() const { return leveldb::Slice((char const*)m_data, m_count * sizeof(_T)); } diff --git a/libethereum/AddressState.h b/libethereum/AddressState.h index 2ccdbd53b..bc4aa6df0 100644 --- a/libethereum/AddressState.h +++ b/libethereum/AddressState.h @@ -21,8 +21,9 @@ #pragma once -#include -#include +#include +#include +#include namespace eth { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 5a5804637..871d773eb 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -22,9 +22,9 @@ #include "BlockChain.h" #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index daa19f783..fff1bc7e3 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -22,7 +22,7 @@ #pragma once #include -#include +#include #include #include #include "AddressState.h" diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 3a36d87fe..3f73df2a7 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -23,7 +23,6 @@ include_directories(${LEVELDB_ID}) target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} ethsupport) target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index cb7d487c5..d7e75121c 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "Defaults.h" #include "PeerServer.h" using namespace std; diff --git a/libethereum/Client.h b/libethereum/Client.h index 0d61274a3..24a9670b8 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include "BlockChain.h" #include "TransactionQueue.h" diff --git a/libethereum/Defaults.cpp b/libethereum/Defaults.cpp index c72e7db83..e78156094 100644 --- a/libethereum/Defaults.cpp +++ b/libethereum/Defaults.cpp @@ -21,7 +21,7 @@ #include "Defaults.h" -#include +#include using namespace std; using namespace eth; diff --git a/libethereum/Defaults.h b/libethereum/Defaults.h index 0ce66dab6..d4bd5322f 100644 --- a/libethereum/Defaults.h +++ b/libethereum/Defaults.h @@ -21,7 +21,7 @@ #pragma once -#include +#include namespace eth { diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 5dd31b69a..b87c40541 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -21,7 +21,7 @@ #pragma once -#include +#include #include #include "Transaction.h" diff --git a/libethereum/PeerNetwork.h b/libethereum/PeerNetwork.h index 8e05696d3..7f6b00b5d 100644 --- a/libethereum/PeerNetwork.h +++ b/libethereum/PeerNetwork.h @@ -27,8 +27,8 @@ #include #include #include -#include -#include +#include +#include namespace ba = boost::asio; namespace bi = boost::asio::ip; diff --git a/libethereum/PeerServer.cpp b/libethereum/PeerServer.cpp index 0219802a2..aecaf1482 100644 --- a/libethereum/PeerServer.cpp +++ b/libethereum/PeerServer.cpp @@ -34,8 +34,8 @@ #include #include #include -#include -#include +#include +#include #include #include "BlockChain.h" #include "TransactionQueue.h" diff --git a/libethereum/PeerSession.cpp b/libethereum/PeerSession.cpp index 956e49432..ad3ec673e 100644 --- a/libethereum/PeerSession.cpp +++ b/libethereum/PeerSession.cpp @@ -22,7 +22,7 @@ #include "PeerSession.h" #include -#include +#include #include #include "BlockChain.h" #include "PeerServer.h" diff --git a/libethereum/PeerSession.h b/libethereum/PeerSession.h index ddc5d8771..e00a1e111 100644 --- a/libethereum/PeerSession.h +++ b/libethereum/PeerSession.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include "PeerNetwork.h" diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 07e71dc28..77f1088b8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libethereum/State.h b/libethereum/State.h index fd3fc89e5..59bd423fc 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -24,9 +24,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 1f7e0fbc1..b60cf115e 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -20,8 +20,8 @@ */ #include -#include -#include +#include +#include #include #include "Transaction.h" using namespace std; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index b0ecb43f0..e3384c540 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -21,7 +21,8 @@ #pragma once -#include +#include +#include #include namespace eth diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 2019a073b..f63384926 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -21,7 +21,7 @@ #include "TransactionQueue.h" -#include +#include #include #include "Transaction.h" using namespace std; diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index cd777c6b4..0c52370b3 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -21,7 +21,7 @@ #pragma once -#include +#include #include "Transaction.h" namespace eth diff --git a/libevm/CMakeLists.txt b/libevm/CMakeLists.txt index 2aae2c76d..257710b56 100644 --- a/libevm/CMakeLists.txt +++ b/libevm/CMakeLists.txt @@ -22,7 +22,8 @@ include_directories(${MINIUPNPC_ID}) include_directories(${LEVELDB_ID}) target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} ethsupport) +target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} ethential) target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 0ec578734..88817aea8 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -21,7 +21,7 @@ #pragma once -#include +#include #include #include diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index a344b80cc..341c81f8c 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -21,7 +21,7 @@ #pragma once -#include +#include namespace eth { diff --git a/libevm/VM.h b/libevm/VM.h index ba97592e6..b1d387708 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -22,9 +22,10 @@ #pragma once #include -#include +#include #include -#include +#include +#include #include #include "FeeStructure.h" #include "ExtVMFace.h" diff --git a/libevmface/CMakeLists.txt b/libevmface/CMakeLists.txt new file mode 100644 index 000000000..30091074d --- /dev/null +++ b/libevmface/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_policy(SET CMP0015 NEW) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") + +aux_source_directory(. SRC_LIST) + +set(EXECUTABLE evmface) + +if(APPLE) + # set(CMAKE_INSTALL_PREFIX ../lib) + add_library(${EXECUTABLE} SHARED ${SRC_LIST}) +else() + add_library(${EXECUTABLE} ${SRC_LIST}) +endif() +file(GLOB HEADERS "*.h") + +include_directories(..) + +target_link_libraries(${EXECUTABLE} ethential) +target_link_libraries(${EXECUTABLE} gmp) + + +if(${TARGET_PLATFORM} STREQUAL "w64") + include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) + target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) + target_link_libraries(${EXECUTABLE} iphlpapi) + target_link_libraries(${EXECUTABLE} ws2_32) + target_link_libraries(${EXECUTABLE} mswsock) + target_link_libraries(${EXECUTABLE} shlwapi) +elseif (APPLE) + # Latest mavericks boost libraries only come with -mt + find_package(Threads REQUIRED) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +elseif (UNIX) + target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +else () + target_link_libraries(${EXECUTABLE} boost_thread) + find_package(Threads REQUIRED) + target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) +endif () + +if (UNIX) + FIND_PACKAGE(Boost 1.53 REQUIRED COMPONENTS thread date_time system filesystem program_options signals serialization chrono unit_test_framework locale) +endif() + +message("Installation path: ${CMAKE_INSTALL_PREFIX}") + +install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/libethcore/Instruction.cpp b/libevmface/Instruction.cpp similarity index 99% rename from libethcore/Instruction.cpp rename to libevmface/Instruction.cpp index 0bea56656..7ee28b0be 100644 --- a/libethcore/Instruction.cpp +++ b/libevmface/Instruction.cpp @@ -21,7 +21,7 @@ #include "Instruction.h" -#include "CommonEth.h" +#include using namespace std; using namespace eth; diff --git a/libethcore/Instruction.h b/libevmface/Instruction.h similarity index 97% rename from libethcore/Instruction.h rename to libevmface/Instruction.h index e5a186d78..a3ad334b1 100644 --- a/libethcore/Instruction.h +++ b/libevmface/Instruction.h @@ -21,8 +21,8 @@ #pragma once -#include -#include "Exceptions.h" +#include +#include namespace boost { namespace spirit { class utree; } } namespace sp = boost::spirit; diff --git a/liblll/Assembly.cpp b/liblll/Assembly.cpp index 0de16982f..0fa125378 100644 --- a/liblll/Assembly.cpp +++ b/liblll/Assembly.cpp @@ -21,7 +21,7 @@ #include "Assembly.h" -#include +#include #include using namespace std; diff --git a/liblll/Assembly.h b/liblll/Assembly.h index 3907f69fd..29f899c0e 100644 --- a/liblll/Assembly.h +++ b/liblll/Assembly.h @@ -23,8 +23,9 @@ #include #include -#include -#include +#include +#include +#include #include "Exceptions.h" namespace eth diff --git a/liblll/CMakeLists.txt b/liblll/CMakeLists.txt index dc5fc2221..4117e6edc 100644 --- a/liblll/CMakeLists.txt +++ b/liblll/CMakeLists.txt @@ -18,17 +18,10 @@ endif() file(GLOB HEADERS "*.h") include_directories(..) -include_directories(${MINIUPNPC_ID}) -include_directories(${LEVELDB_ID}) - -target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} ethsupport) -target_link_libraries(${EXECUTABLE} secp256k1) -target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) +target_link_libraries(${EXECUTABLE} ethential) +target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} gmp) - if(${TARGET_PLATFORM} STREQUAL "w64") include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) target_link_libraries(${EXECUTABLE} cryptopp) diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 9284c1f31..2ad23471d 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -24,8 +24,8 @@ #include #include -#include -#include +#include +#include #include #include "CompilerState.h" using namespace std; diff --git a/liblll/CodeFragment.h b/liblll/CodeFragment.h index 8e3ff1d7d..b9d44c030 100644 --- a/liblll/CodeFragment.h +++ b/liblll/CodeFragment.h @@ -21,8 +21,8 @@ #pragma once -#include -#include +#include +#include #include "Assembly.h" #include "Exceptions.h" diff --git a/liblll/Compiler.h b/liblll/Compiler.h index 395d79094..da84a2fea 100644 --- a/liblll/Compiler.h +++ b/liblll/Compiler.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace eth { diff --git a/liblll/Parser.h b/liblll/Parser.h index 059ffe6a2..5286c3e8a 100644 --- a/liblll/Parser.h +++ b/liblll/Parser.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace boost { namespace spirit { class utree; } } namespace sp = boost::spirit; diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 25c627f54..9033b92cd 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -1,9 +1,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index bfc973a0d..5334fd73f 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include namespace eth { diff --git a/libethsupport/CMakeLists.txt b/libserpent/CMakeLists.txt similarity index 90% rename from libethsupport/CMakeLists.txt rename to libserpent/CMakeLists.txt index 07458260a..0deb6f604 100644 --- a/libethsupport/CMakeLists.txt +++ b/libserpent/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -set(EXECUTABLE ethsupport) +set(EXECUTABLE serpent) if(APPLE) # set(CMAKE_INSTALL_PREFIX ../lib) @@ -18,12 +18,10 @@ endif() file(GLOB HEADERS "*.h") include_directories(..) -include_directories(${MINIUPNPC_ID}) -include_directories(${LEVELDB_ID}) -target_link_libraries(${EXECUTABLE} secp256k1) -target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) +target_link_libraries(${EXECUTABLE} ethential) +target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} gmp) diff --git a/libserpent/bignum.cpp b/libserpent/bignum.cpp new file mode 100644 index 000000000..29315b871 --- /dev/null +++ b/libserpent/bignum.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include "bignum.h" + +//Integer to string conversion +std::string intToDecimal(int branch) { + if (branch < 10) return nums.substr(branch, 1); + else return intToDecimal(branch / 10) + nums.substr(branch % 10,1); +} + +//Add two strings representing decimal values +std::string decimalAdd(std::string a, std::string b) { + std::string o = a; + while (b.length() < a.length()) b = "0" + b; + while (o.length() < b.length()) o = "0" + o; + bool carry = false; + for (int i = o.length() - 1; i >= 0; i--) { + o[i] = o[i] + b[i] - '0'; + if (carry) o[i]++; + if (o[i] > '9') { + o[i] -= 10; + carry = true; + } + else carry = false; + } + if (carry) o = "1" + o; + return o; +} + +//Helper function for decimalMul +std::string decimalDigitMul(std::string a, int dig) { + if (dig == 0) return "0"; + else return decimalAdd(a, decimalDigitMul(a, dig - 1)); +} + +//Multiply two strings representing decimal values +std::string decimalMul(std::string a, std::string b) { + std::string o = "0"; + for (unsigned i = 0; i < b.length(); i++) { + std::string n = decimalDigitMul(a, b[i] - '0'); + if (n != "0") { + for (unsigned j = i + 1; j < b.length(); j++) n += "0"; + } + o = decimalAdd(o, n); + } + return o; +} + +//Is a greater than b? Flag allows equality +bool decimalGt(std::string a, std::string b, bool eqAllowed) { + if (a == b) return eqAllowed; + return (a.length() > b.length()) || (a.length() >= b.length() && a > b); +} + +//Subtract the two strings representing decimal values +std::string decimalSub(std::string a, std::string b) { + if (b == "0") return a; + if (b == a) return "0"; + while (b.length() < a.length()) b = "0" + b; + std::string c = b; + for (unsigned i = 0; i < c.length(); i++) c[i] = '0' + ('9' - c[i]); + std::string o = decimalAdd(decimalAdd(a, c).substr(1), "1"); + while (o.size() > 1 && o[0] == '0') o = o.substr(1); + return o; +} + +//Divide the two strings representing decimal values +std::string decimalDiv(std::string a, std::string b) { + std::string c = b; + if (decimalGt(c, a)) return "0"; + int zeroes = -1; + while (decimalGt(a, c, true)) { + zeroes += 1; + c = c + "0"; + } + c = c.substr(0, c.size() - 1); + std::string quot = "0"; + while (decimalGt(a, c, true)) { + a = decimalSub(a, c); + quot = decimalAdd(quot, "1"); + } + for (int i = 0; i < zeroes; i++) quot += "0"; + return decimalAdd(quot, decimalDiv(a, b)); +} + +//Modulo the two strings representing decimal values +std::string decimalMod(std::string a, std::string b) { + return decimalSub(a, decimalMul(decimalDiv(a, b), b)); +} + +//String to int conversion +int decimalToInt(std::string a) { + if (a.size() == 0) return 0; + else return (a[a.size() - 1] - '0') + + decimalToInt(a.substr(0,a.size()-1)) * 10; +} diff --git a/libserpent/bignum.h b/libserpent/bignum.h new file mode 100644 index 000000000..a12929752 --- /dev/null +++ b/libserpent/bignum.h @@ -0,0 +1,30 @@ +#ifndef ETHSERP_BIGNUM +#define ETHSERP_BIGNUM + +const std::string nums = "0123456789"; + +const std::string tt256 = +"115792089237316195423570985008687907853269984665640564039457584007913129639936" +; + +const std::string tt255 = +"57896044618658097711785492504343953926634992332820282019728792003956564819968" +; + +std::string intToDecimal(int branch); + +std::string decimalAdd(std::string a, std::string b); + +std::string decimalMul(std::string a, std::string b); + +std::string decimalSub(std::string a, std::string b); + +std::string decimalDiv(std::string a, std::string b); + +std::string decimalMod(std::string a, std::string b); + +bool decimalGt(std::string a, std::string b, bool eqAllowed=false); + +int decimalToInt(std::string a); + +#endif diff --git a/libserpent/compiler.cpp b/libserpent/compiler.cpp new file mode 100644 index 000000000..731e018f0 --- /dev/null +++ b/libserpent/compiler.cpp @@ -0,0 +1,407 @@ +#include +#include +#include +#include +#include "util.h" +#include "bignum.h" +#include "opcodes.h" + +struct programAux { + std::map vars; + bool allocUsed; + bool calldataUsed; + int step; + int labelLength; +}; + +struct programData { + programAux aux; + Node code; +}; + +programAux Aux() { + programAux o; + o.allocUsed = false; + o.calldataUsed = false; + o.step = 0; + return o; +} + +programData pd(programAux aux = Aux(), Node code=token("_")) { + programData o; + o.aux = aux; + o.code = code; + return o; +} + +Node multiToken(Node nodes[], int len, Metadata met) { + std::vector out; + for (int i = 0; i < len; i++) { + out.push_back(nodes[i]); + } + return astnode("_", out, met); +} + +Node finalize(programData c); + +// Turns LLL tree into tree of code fragments +programData opcodeify(Node node, programAux aux=Aux()) { + std::string symb = "_"+mkUniqueToken(); + Metadata m = node.metadata; + // Numbers + if (node.type == TOKEN) { + return pd(aux, nodeToNumeric(node)); + } + else if (node.val == "ref" || node.val == "get" || node.val == "set") { + std::string varname = node.args[0].val; + if (!aux.vars.count(varname)) { + aux.vars[varname] = intToDecimal(aux.vars.size() * 32); + } + if (varname == "msg.data") aux.calldataUsed = true; + // Set variable + if (node.val == "set") { + programData sub = opcodeify(node.args[1], aux); + Node nodelist[] = { + sub.code, + token(aux.vars[varname], m), + token("MSTORE", m), + }; + return pd(sub.aux, multiToken(nodelist, 3, m)); + } + // Get variable + else if (node.val == "get") { + Node nodelist[] = + { token(aux.vars[varname], m), token("MLOAD", m) }; + return pd(aux, multiToken(nodelist, 2, m)); + } + // Refer variable + else return pd(aux, token(aux.vars[varname], m)); + } + // Code blocks + if (node.val == "lll" && node.args.size() == 2) { + if (node.args[1].val != "0") aux.allocUsed = true; + std::vector o; + o.push_back(finalize(opcodeify(node.args[0]))); + programData sub = opcodeify(node.args[1], aux); + Node code = astnode("____CODE", o, m); + Node nodelist[] = { + token("$begincode"+symb+".endcode"+symb, m), token("DUP", m), + sub.code, + token("$begincode"+symb, m), token("CODECOPY", m), + token("$endcode"+symb, m), token("JUMP", m), + token("~begincode"+symb, m), code, token("~endcode"+symb, m) + }; + return pd(sub.aux, multiToken(nodelist, 10, m)); + } + std::vector subs; + for (unsigned i = 0; i < node.args.size(); i++) { + programData sub = opcodeify(node.args[i], aux); + aux = sub.aux; + subs.push_back(sub.code); + } + // Seq of multiple statements + if (node.val == "seq") { + return pd(aux, astnode("_", subs, m)); + } + // 2-part conditional (if gets rewritten to unless in rewrites) + else if (node.val == "unless" && node.args.size() == 2) { + Node nodelist[] = { + subs[0], + token("$endif"+symb, m), token("JUMPI", m), + subs[1], + token("~endif"+symb, m) + }; + return pd(aux, multiToken(nodelist, 5, m)); + } + // 3-part conditional + else if (node.val == "if" && node.args.size() == 3) { + Node nodelist[] = { + subs[0], + token("NOT", m), token("$else"+symb, m), token("JUMPI", m), + subs[1], + token("$endif"+symb, m), token("JUMP", m), token("~else"+symb, m), + subs[2], + token("~endif"+symb, m) + }; + return pd(aux, multiToken(nodelist, 10, m)); + } + // While (rewritten to this in rewrites) + else if (node.val == "until") { + Node nodelist[] = { + token("~beg"+symb, m), + subs[0], + token("$end"+symb, m), token("JUMPI", m), + subs[1], + token("$beg"+symb, m), token("JUMP", m), token("~end"+symb, m) + }; + return pd(aux, multiToken(nodelist, 8, m)); + } + // Memory allocations + else if (node.val == "alloc") { + aux.allocUsed = true; + Node nodelist[] = { + subs[0], + token("MSIZE", m), token("SWAP", m), token("MSIZE", m), + token("ADD", m), token("1", m), token("SWAP", m), token("SUB", m), + token("0", m), token("SWAP", m), token("MSTORE8", m) + }; + return pd(aux, multiToken(nodelist, 11, m)); + } + // Array literals + else if (node.val == "array_lit") { + aux.allocUsed = true; + std::vector nodes; + if (!subs.size()) { + nodes.push_back(token("MSIZE", m)); + return pd(aux, astnode("_", nodes, m)); + } + nodes.push_back(token("MSIZE", m)); + nodes.push_back(token("0", m)); + nodes.push_back(token("MSIZE", m)); + nodes.push_back(token(intToDecimal(subs.size() * 32 - 1), m)); + nodes.push_back(token("ADD", m)); + nodes.push_back(token("MSTORE8", m)); + for (unsigned i = 0; i < subs.size(); i++) { + nodes.push_back(token("DUP", m)); + nodes.push_back(subs[i]); + nodes.push_back(token("SWAP", m)); + if (i > 0) { + nodes.push_back(token(intToDecimal(i * 32), m)); + nodes.push_back(token("ADD", m)); + } + nodes.push_back(token("MSTORE", m)); + } + return pd(aux, astnode("_", nodes, m)); + } + // All other functions/operators + else { + std::vector subs2; + while (subs.size()) { + subs2.push_back(subs.back()); + subs.pop_back(); + } + subs2.push_back(token(upperCase(node.val), m)); + return pd(aux, astnode("_", subs2, m)); + } +} + +// Adds necessary wrappers to a program +Node finalize(programData c) { + std::vector bottom; + Metadata m = c.code.metadata; + // If we are using both alloc and variables, we need to pre-zfill + // some memory + if (c.aux.allocUsed && c.aux.vars.size() > 0) { + Node nodelist[] = { + token("0", m), + token(intToDecimal(c.aux.vars.size() * 32 - 1)), + token("MSTORE8", m) + }; + bottom.push_back(multiToken(nodelist, 3, m)); + } + // If msg.data is being used as an array, then we need to copy it + if (c.aux.calldataUsed) { + Node nodelist[] = { + token("MSIZE", m), token("CALLDATASIZE", m), token("MSIZE", m), + token("0", m), token("CALLDATACOPY", m), + token(c.aux.vars["msg.data"], m), token("MSTORE", m) + }; + bottom.push_back(multiToken(nodelist, 7, m)); + } + // The actual code + bottom.push_back(c.code); + return astnode("_", bottom, m); +} + +//LLL -> code fragment tree +Node buildFragmentTree(Node node) { + return finalize(opcodeify(node)); +} + + +// Builds a dictionary mapping labels to variable names +programAux buildDict(Node program, programAux aux, int labelLength) { + Metadata m = program.metadata; + // Token + if (program.type == TOKEN) { + if (isNumberLike(program)) { + aux.step += 1 + toByteArr(program.val, m).size(); + } + else if (program.val[0] == '~') { + aux.vars[program.val.substr(1)] = intToDecimal(aux.step); + } + else if (program.val[0] == '$') { + aux.step += labelLength + 1; + } + else aux.step += 1; + } + // A sub-program (ie. LLL) + else if (program.val == "____CODE") { + programAux auks = Aux(); + for (unsigned i = 0; i < program.args.size(); i++) { + auks = buildDict(program.args[i], auks, labelLength); + } + for (std::map::iterator it=auks.vars.begin(); + it != auks.vars.end(); + it++) { + aux.vars[(*it).first] = (*it).second; + } + aux.step += auks.step; + } + // Normal sub-block + else { + for (unsigned i = 0; i < program.args.size(); i++) { + aux = buildDict(program.args[i], aux, labelLength); + } + } + return aux; +} + +// Applies that dictionary +Node substDict(Node program, programAux aux, int labelLength) { + Metadata m = program.metadata; + std::vector out; + std::vector inner; + if (program.type == TOKEN) { + if (program.val[0] == '$') { + std::string tokStr = "PUSH"+intToDecimal(labelLength); + out.push_back(token(tokStr, m)); + int dotLoc = program.val.find('.'); + if (dotLoc == -1) { + std::string val = aux.vars[program.val.substr(1)]; + inner = toByteArr(val, m, labelLength); + } + else { + std::string start = aux.vars[program.val.substr(1, dotLoc-1)], + end = aux.vars[program.val.substr(dotLoc + 1)], + dist = decimalSub(end, start); + inner = toByteArr(dist, m, labelLength); + } + out.push_back(astnode("_", inner, m)); + } + else if (program.val[0] == '~') { } + else if (isNumberLike(program)) { + inner = toByteArr(program.val, m); + out.push_back(token("PUSH"+intToDecimal(inner.size()))); + out.push_back(astnode("_", inner, m)); + } + else return program; + } + else { + for (unsigned i = 0; i < program.args.size(); i++) { + Node n = substDict(program.args[i], aux, labelLength); + if (n.type == TOKEN || n.args.size()) out.push_back(n); + } + } + return astnode("_", out, m); +} + +// Compiled fragtree -> compiled fragtree without labels +Node dereference(Node program) { + int sz = treeSize(program) * 4; + int labelLength = 1; + while (sz >= 256) { labelLength += 1; sz /= 256; } + programAux aux = buildDict(program, Aux(), labelLength); + return substDict(program, aux, labelLength); +} + +// Dereferenced fragtree -> opcodes +std::vector flatten(Node derefed) { + std::vector o; + if (derefed.type == TOKEN) { + o.push_back(derefed); + } + else { + for (unsigned i = 0; i < derefed.args.size(); i++) { + std::vector oprime = flatten(derefed.args[i]); + for (unsigned j = 0; j < oprime.size(); j++) o.push_back(oprime[j]); + } + } + return o; +} + +// Opcodes -> bin +std::string serialize(std::vector codons) { + std::string o; + for (unsigned i = 0; i < codons.size(); i++) { + int v; + if (isNumberLike(codons[i])) { + v = decimalToInt(codons[i].val); + } + else if (codons[i].val.substr(0,4) == "PUSH") { + v = 95 + decimalToInt(codons[i].val.substr(4)); + } + else { + v = opcode(codons[i].val); + } + o += (char)v; + } + return o; +} + +// Bin -> opcodes +std::vector deserialize(std::string ser) { + std::vector o; + int backCount = 0; + for (unsigned i = 0; i < ser.length(); i++) { + unsigned char v = (unsigned char)ser[i]; + std::string oper = op((int)v); + if (oper != "" && backCount <= 0) o.push_back(token(oper)); + else if (v >= 96 && v < 128 && backCount <= 0) { + o.push_back(token("PUSH"+intToDecimal(v - 95))); + } + else o.push_back(token(intToDecimal(v))); + if (v >= 96 && v < 128 && backCount <= 0) { + backCount = v - 95; + } + else backCount--; + } + return o; +} + +// Fragtree -> bin +std::string assemble(Node fragTree) { + return serialize(flatten(dereference(fragTree))); +} + +// Fragtree -> tokens +std::vector prettyAssemble(Node fragTree) { + return flatten(dereference(fragTree)); +} + +// LLL -> bin +std::string compileLLL(Node program) { + return assemble(buildFragmentTree(program)); +} + +// LLL -> tokens +std::vector prettyCompileLLL(Node program) { + return prettyAssemble(buildFragmentTree(program)); +} + +// Converts a list of integer values to binary transaction data +std::string encodeDatalist(std::vector vals) { + std::string o; + for (unsigned i = 0; i < vals.size(); i++) { + std::vector n = toByteArr(strToNumeric(vals[i]), Metadata(), 32); + for (unsigned j = 0; j < n.size(); j++) { + int v = decimalToInt(n[j].val); + o += (char)v; + } + } + return o; +} + +// Converts binary transaction data into a list of integer values +std::vector decodeDatalist(std::string ser) { + std::vector out; + for (unsigned i = 0; i < ser.length(); i+= 32) { + std::string o = "0"; + for (unsigned j = i; j < i + 32; j++) { + int vj = (int)(unsigned char)ser[j]; + o = decimalAdd(decimalMul(o, "256"), intToDecimal(vj)); + } + out.push_back(o); + } + return out; +} diff --git a/libserpent/compiler.h b/libserpent/compiler.h new file mode 100644 index 000000000..aecaa3718 --- /dev/null +++ b/libserpent/compiler.h @@ -0,0 +1,43 @@ +#ifndef ETHSERP_COMPILER +#define ETHSERP_COMPILER + +#include +#include +#include +#include +#include "util.h" + +// Compiled fragtree -> compiled fragtree without labels +Node dereference(Node program); + +// LLL -> fragtree +Node buildFragmentTree(Node program); + +// Dereferenced fragtree -> opcodes +std::vector flatten(Node derefed); + +// opcodes -> bin +std::string serialize(std::vector codons); + +// Fragtree -> bin +std::string assemble(Node fragTree); + +// Fragtree -> opcodes +std::vector prettyAssemble(Node fragTree); + +// LLL -> bin +std::string compileLLL(Node program); + +// LLL -> opcodes +std::vector prettyCompileLLL(Node program); + +// bin -> opcodes +std::vector deserialize(std::string ser); + +// Converts a list of integer values to binary transaction data +std::string encodeDatalist(std::vector vals); + +// Converts binary transaction data into a list of integer values +std::vector decodeDatalist(std::string ser); + +#endif diff --git a/libserpent/example.cpp b/libserpent/example.cpp new file mode 100644 index 000000000..1ce2590d0 --- /dev/null +++ b/libserpent/example.cpp @@ -0,0 +1,11 @@ +#include +#include +#include + +using namespace std; + +int main() { + cout << printAST(compileToLLL(get_file_contents("examples/namecoin.se"))) << "\n"; + cout << decimalSub("10234", "10234") << "\n"; + cout << decimalSub("10234", "10233") << "\n"; +} diff --git a/libserpent/funcs.cpp b/libserpent/funcs.cpp new file mode 100644 index 000000000..e80fcff06 --- /dev/null +++ b/libserpent/funcs.cpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include "funcs.h" +#include "bignum.h" +#include "util.h" +#include "parser.h" +#include "lllparser.h" +#include "compiler.h" +#include "rewriter.h" +#include "tokenize.h" + +Node compileToLLL(std::string input) { + return rewrite(parseSerpent(input)); +} + +std::string compile(std::string input) { + return compileLLL(compileToLLL(input)); +} + +std::vector prettyCompile(std::string input) { + return prettyCompileLLL(compileToLLL(input)); +} diff --git a/libserpent/funcs.h b/libserpent/funcs.h new file mode 100644 index 000000000..0f3355ec8 --- /dev/null +++ b/libserpent/funcs.h @@ -0,0 +1,29 @@ +#include +#include +#include +#include "bignum.h" +#include "util.h" +#include "parser.h" +#include "lllparser.h" +#include "compiler.h" +#include "rewriter.h" +#include "tokenize.h" + +// Function listing: +// +// parseSerpent (serpent -> AST) std::string -> Node +// parseLLL (LLL -> AST) std::string -> Node +// rewrite (apply rewrite rules) Node -> Node +// compileToLLL (serpent -> LLL) std::string -> Node +// compileLLL (LLL -> EVMhex) Node -> std::string +// prettyCompileLLL (LLL -> EVMasm) Node -> std::vector +// prettyCompile (serpent -> EVMasm) std::string -> std::vector>Node> +// compile (serpent -> EVMhex) std::string -> std::string +// get_file_contents (filename -> file) std::string -> std::string +// exists (does file exist?) std::string -> bool + +Node compileToLLL(std::string input); + +std::string compile(std::string input); + +std::vector prettyCompile(std::string input); diff --git a/libserpent/lllparser.cpp b/libserpent/lllparser.cpp new file mode 100644 index 000000000..812ef4a48 --- /dev/null +++ b/libserpent/lllparser.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include "util.h" +#include "lllparser.h" +#include "tokenize.h" + +struct _parseOutput { + Node node; + int newpos; +}; + +// Helper, returns subtree and position of start of next node +_parseOutput _parse(std::vector inp, int pos) { + Metadata met = inp[pos].metadata; + _parseOutput o; + // Bracket: keep grabbing tokens until we get to the + // corresponding closing bracket + if (inp[pos].val == "(" || inp[pos].val == "[") { + std::string fun, rbrack; + std::vector args; + pos += 1; + if (inp[pos].val == "[") { + fun = "access"; + rbrack = "]"; + } + else rbrack = ")"; + // First argument is the function + while (inp[pos].val != ")") { + _parseOutput po = _parse(inp, pos); + if (fun.length() == 0 && po.node.type == 1) { + std::cerr << "Error: first arg must be function\n"; + fun = po.node.val; + } + else if (fun.length() == 0) { + fun = po.node.val; + } + else { + args.push_back(po.node); + } + pos = po.newpos; + } + o.newpos = pos + 1; + o.node = astnode(fun, args, met); + } + // Normal token, return it and advance to next token + else { + o.newpos = pos + 1; + o.node = token(inp[pos].val, met); + } + return o; +} + +// stream of tokens -> lisp parse tree +Node parseLLLTokenStream(std::vector inp) { + _parseOutput o = _parse(inp, 0); + return o.node; +} + +// Parses LLL +Node parseLLL(std::string s, bool allowFileRead) { + std::string input = s; + std::string file = "main"; + if (exists(s) && allowFileRead) { + file = s; + input = get_file_contents(s); + } + return parseLLLTokenStream(tokenize(s, Metadata(file, 0, 0))); +} diff --git a/libserpent/lllparser.h b/libserpent/lllparser.h new file mode 100644 index 000000000..4bfa7b82e --- /dev/null +++ b/libserpent/lllparser.h @@ -0,0 +1,13 @@ +#ifndef ETHSERP_LLLPARSER +#define ETHSERP_LLLPARSER + +#include +#include +#include +#include +#include "util.h" + +// LLL text -> parse tree +Node parseLLL(std::string s, bool allowFileRead=false); + +#endif diff --git a/libserpent/opcodes.h b/libserpent/opcodes.h new file mode 100644 index 000000000..6b42df97a --- /dev/null +++ b/libserpent/opcodes.h @@ -0,0 +1,91 @@ +#ifndef ETHSERP_OPCODES +#define ETHSERP_OPCODES + +#include +#include +#include +#include + +std::map opcodes; +std::map reverseOpcodes; + +// Fetches everything EXCEPT PUSH1..32 +std::pair _opcode(std::string ops, int opi) { + if (!opcodes.size()) { + opcodes["STOP"] = 0x00; + opcodes["ADD"] = 0x01; + opcodes["MUL"] = 0x02; + opcodes["SUB"] = 0x03; + opcodes["DIV"] = 0x04; + opcodes["SDIV"] = 0x05; + opcodes["MOD"] = 0x06; + opcodes["SMOD"] = 0x07; + opcodes["EXP"] = 0x08; + opcodes["NEG"] = 0x09; + opcodes["LT"] = 0x0a; + opcodes["GT"] = 0x0b; + opcodes["SLT"] = 0x0c; + opcodes["SGT"] = 0x0d; + opcodes["EQ"] = 0x0e; + opcodes["NOT"] = 0x0f; + opcodes["AND"] = 0x10; + opcodes["OR"] = 0x11; + opcodes["XOR"] = 0x12; + opcodes["BYTE"] = 0x13; + opcodes["SHA3"] = 0x20; + opcodes["ADDRESS"] = 0x30; + opcodes["BALANCE"] = 0x31; + opcodes["ORIGIN"] = 0x32; + opcodes["CALLER"] = 0x33; + opcodes["CALLVALUE"] = 0x34; + opcodes["CALLDATALOAD"] = 0x35; + opcodes["CALLDATASIZE"] = 0x36; + opcodes["CALLDATACOPY"] = 0x37; + opcodes["CODESIZE"] = 0x38; + opcodes["CODECOPY"] = 0x39; + opcodes["GASPRICE"] = 0x3a; + opcodes["PREVHASH"] = 0x40; + opcodes["COINBASE"] = 0x41; + opcodes["TIMESTAMP"] = 0x42; + opcodes["NUMBER"] = 0x43; + opcodes["DIFFICULTY"] = 0x44; + opcodes["GASLIMIT"] = 0x45; + opcodes["POP"] = 0x50; + opcodes["DUP"] = 0x51; + opcodes["SWAP"] = 0x52; + opcodes["MLOAD"] = 0x53; + opcodes["MSTORE"] = 0x54; + opcodes["MSTORE8"] = 0x55; + opcodes["SLOAD"] = 0x56; + opcodes["SSTORE"] = 0x57; + opcodes["JUMP"] = 0x58; + opcodes["JUMPI"] = 0x59; + opcodes["PC"] = 0x5a; + opcodes["MSIZE"] = 0x5b; + opcodes["GAS"] = 0x5c; + opcodes["CREATE"] = 0xf0; + opcodes["CALL"] = 0xf1; + opcodes["RETURN"] = 0xf2; + opcodes["SUICIDE"] = 0xff; + for (std::map::iterator it=opcodes.begin(); + it != opcodes.end(); + it++) { + reverseOpcodes[(*it).second] = (*it).first; + } + } + std::string op; + int opcode; + op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : ""; + opcode = opcodes.count(ops) ? opcodes[ops] : -1; + return std::pair(op, opcode); +} + +int opcode(std::string op) { + return _opcode(op, 0).second; +} + +std::string op(int opcode) { + return _opcode("", opcode).first; +} + +#endif diff --git a/libserpent/parser.cpp b/libserpent/parser.cpp new file mode 100644 index 000000000..2a3efcc55 --- /dev/null +++ b/libserpent/parser.cpp @@ -0,0 +1,387 @@ +#include +#include +#include +#include +#include "util.h" +#include "parser.h" +#include "tokenize.h" + +// Extended BEDMAS precedence order +int precedence(Node tok) { + std::string v = tok.val; + if (v == "!" || v == "not") return 0; + else if (v=="^" || v == "**") return 1; + else if (v=="*" || v=="/" || v=="@/" || v=="%" || v=="@%") return 2; + else if (v=="+" || v=="-") return 3; + else if (v=="<" || v==">" || v=="<=" || v==">=") return 4; + else if (v=="@<" || v=="@>" || v=="@<=" || v=="@>=") return 4; + else if (v=="&" || v=="|" || v=="xor" || v=="==") return 5; + else if (v=="&&" || v=="and") return 6; + else if (v=="||" || v=="or") return 7; + else if (v=="=") return 10; + else if (v=="+=" || v=="-=" || v=="*=" || v=="/=" || v=="%=") return 10; + else if (v=="@/=" || v=="@%=") return 10; + else return -1; +} + +// Token classification for shunting-yard purposes +int toktype(Node tok) { + if (tok.type == ASTNODE) return COMPOUND; + std::string v = tok.val; + if (v == "(" || v == "[") return LPAREN; + else if (v == ")" || v == "]") return RPAREN; + else if (v == ",") return COMMA; + else if (v == ":") return COLON; + else if (v == "!" || v == "not") return UNARY_OP; + else if (precedence(tok) >= 0) return BINARY_OP; + if (tok.val[0] != '"' && tok.val[0] != '\'') { + for (unsigned i = 0; i < tok.val.length(); i++) { + if (chartype(tok.val[i]) == SYMB) { + err("Invalid symbol: "+tok.val, tok.metadata); + } + } + } + return ALPHANUM; +} + + +// Converts to reverse polish notation +std::vector shuntingYard(std::vector tokens) { + std::vector iq; + for (int i = tokens.size() - 1; i >= 0; i--) { + iq.push_back(tokens[i]); + } + std::vector oq; + std::vector stack; + Node prev, tok; + int prevtyp, toktyp; + + while (iq.size()) { + prev = tok; + prevtyp = toktyp; + tok = iq.back(); + toktyp = toktype(tok); + iq.pop_back(); + // Alphanumerics go straight to output queue + if (toktyp == ALPHANUM) { + oq.push_back(tok); + } + // Left parens go on stack and output queue + else if (toktyp == LPAREN) { + if (prevtyp != ALPHANUM && prevtyp != RPAREN) { + oq.push_back(token("id", tok.metadata)); + } + Node fun = oq.back(); + oq.pop_back(); + oq.push_back(tok); + oq.push_back(fun); + stack.push_back(tok); + } + // If rparen, keep moving from stack to output queue until lparen + else if (toktyp == RPAREN) { + while (stack.size() && toktype(stack.back()) != LPAREN) { + oq.push_back(stack.back()); + stack.pop_back(); + } + if (stack.size()) stack.pop_back(); + oq.push_back(tok); + } + // If binary op, keep popping from stack while higher bedmas precedence + else if (toktyp == UNARY_OP || toktyp == BINARY_OP) { + if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) { + oq.push_back(token("0", tok.metadata)); + } + int prec = precedence(tok); + while (stack.size() + && toktype(stack.back()) == BINARY_OP + && precedence(stack.back()) <= prec) { + oq.push_back(stack.back()); + stack.pop_back(); + } + stack.push_back(tok); + } + // Comma and colon mean finish evaluating the argument + else if (toktyp == COMMA || toktyp == COLON) { + while (stack.size() && toktype(stack.back()) != LPAREN) { + oq.push_back(stack.back()); + stack.pop_back(); + } + if (toktyp == COLON) oq.push_back(tok); + } + } + while (stack.size()) { + oq.push_back(stack.back()); + stack.pop_back(); + } + return oq; +} + +// Converts reverse polish notation into tree +Node treefy(std::vector stream) { + std::vector iq; + for (int i = stream.size() -1; i >= 0; i--) { + iq.push_back(stream[i]); + } + std::vector oq; + while (iq.size()) { + Node tok = iq.back(); + iq.pop_back(); + int typ = toktype(tok); + // If unary, take node off end of oq and wrap it with the operator + // If binary, do the same with two nodes + if (typ == UNARY_OP || typ == BINARY_OP) { + std::vector args; + int rounds = (typ == BINARY_OP) ? 2 : 1; + for (int i = 0; i < rounds; i++) { + if (oq.size() == 0) { + err("Line malformed, not enough args for "+tok.val, + tok.metadata); + } + args.push_back(oq.back()); + oq.pop_back(); + } + std::vector args2; + while (args.size()) { + args2.push_back(args.back()); + args.pop_back(); + } + oq.push_back(astnode(tok.val, args2, tok.metadata)); + } + // If rparen, keep grabbing until we get to an lparen + else if (toktype(tok) == RPAREN) { + std::vector args; + while (1) { + args.push_back(oq.back()); + oq.pop_back(); + if (!oq.size()) err("Bracket without matching", tok.metadata); + if (toktype(oq.back()) == LPAREN) break; + } + oq.pop_back(); + // We represent a[b] as (access a b) + if (tok.val == "]") args.push_back(token("access", tok.metadata)); + std::string fun = args.back().val; + args.pop_back(); + // We represent [1,2,3] as (array_lit 1 2 3) + if (fun == "access" && args.size() && args.back().val == "id") { + fun = "array_lit"; + args.pop_back(); + } + std::vector args2; + while (args.size()) { + args2.push_back(args.back()); + args.pop_back(); + } + // When evaluating 2 + (3 * 5), the shunting yard algo turns that + // into 2 ( id 3 5 * ) +, effectively putting "id" as a dummy + // function where the algo was expecting a function to call the + // thing inside the brackets. This reverses that step + if (fun == "id" && args2.size()) { + oq.push_back(args2[0]); + } + else { + oq.push_back(astnode(fun, args2, tok.metadata)); + } + } + else oq.push_back(tok); + // This is messy, but has to be done. Import/inset other files here + std::string v = oq.back().val; + if ((v == "inset" || v == "import" || v == "create") + && oq.back().args.size() == 1 + && oq.back().args[0].type == TOKEN) { + int lastSlashPos = tok.metadata.file.rfind("/"); + std::string root; + if (lastSlashPos >= 0) + root = tok.metadata.file.substr(0, lastSlashPos) + "/"; + else + root = ""; + std::string filename = oq.back().args[0].val; + filename = filename.substr(1, filename.length() - 2); + if (!exists(root + filename)) + err("File does not exist: "+root + filename, tok.metadata); + oq.back().args.pop_back(); + oq.back().args.push_back(parseSerpent(root + filename)); + } + // Useful for debugging + // for (int i = 0; i < oq.size(); i++) { + // std::cerr << printSimple(oq[i]) << " "; + // } + // std::cerr << "\n"; + } + // Output must have one argument + if (oq.size() == 0) { + err("Output blank", Metadata()); + } + else if (oq.size() > 1) { + err("Multiple expressions or unclosed bracket", oq[1].metadata); + } + + return oq[0]; +} + + +// Parses one line of serpent +Node parseSerpentTokenStream(std::vector s) { + return treefy(shuntingYard(s)); +} + + +// Count spaces at beginning of line +int spaceCount(std::string s) { + unsigned pos = 0; + while (pos < s.length() && (s[pos] == ' ' || s[pos] == '\t')) + pos++; + return pos; +} + +// Is this a command that takes an argument on the same line? +bool bodied(std::string tok) { + return tok == "if" || tok == "elif" || tok == "while"; +} + +// Is this a command that takes an argument as a child block? +bool childBlocked(std::string tok) { + return tok == "if" || tok == "elif" || tok == "else" + || tok == "code" || tok == "shared" || tok == "init" + || tok == "while"; +} + +// Are the two commands meant to continue each other? +bool bodiedContinued(std::string prev, std::string tok) { + return (prev == "if" && tok == "elif") + || (prev == "elif" && tok == "else") + || (prev == "elif" && tok == "elif") + || (prev == "if" && tok == "else") + || (prev == "init" && tok == "code") + || (prev == "shared" && tok == "code") + || (prev == "shared" && tok == "init"); +} + +// Is a line of code empty? +bool isLineEmpty(std::string line) { + std::vector tokens = tokenize(line); + if (!tokens.size() || tokens[0].val == "#" || tokens[0].val == "//") + return true; + return false; +} + +// Parse lines of serpent (helper function) +Node parseLines(std::vector lines, Metadata metadata, int sp) { + std::vector o; + int origLine = metadata.ln; + unsigned i = 0; + while (i < lines.size()) { + metadata.ln = origLine + i; + std::string main = lines[i]; + if (isLineEmpty(main)) { + i += 1; + continue; + } + int spaces = spaceCount(main); + if (spaces != sp) { + err("Indent mismatch", metadata); + } + // Tokenize current line + std::vector tokens = tokenize(main.substr(sp), metadata); + // Remove extraneous tokens, including if / elif + std::vector tokens2; + for (unsigned j = 0; j < tokens.size(); j++) { + if (tokens[j].val == "#" || tokens[j].val == "//") break; + if (j >= 1 || !bodied(tokens[j].val)) { + tokens2.push_back(tokens[j]); + } + } + if (tokens2.size() > 0 && tokens2.back().val == ":") + tokens2.pop_back(); + // Parse current line + Node out = parseSerpentTokenStream(tokens2); + // Parse child block + int childIndent = 999999; + std::vector childBlock; + while (1) { + i++; + if (i >= lines.size()) + break; + bool ile = isLineEmpty(lines[i]); + if (!ile) { + int spaces = spaceCount(lines[i]); + if (spaces <= sp) break; + childBlock.push_back(lines[i]); + if (spaces < childIndent) childIndent = spaces; + } + else childBlock.push_back(""); + } + // Child block empty? + bool cbe = true; + for (unsigned i = 0; i < childBlock.size(); i++) { + if (childBlock[i].length() > 0) { cbe = false; break; } + } + // Bring back if / elif into AST + if (bodied(tokens[0].val)) { + std::vector args; + args.push_back(out); + out = astnode(tokens[0].val, args, out.metadata); + } + // Add child block to AST + if (childBlocked(tokens[0].val)) { + if (cbe) + err("Expected indented child block!", out.metadata); + out.type = ASTNODE; + metadata.ln += 1; + out.args.push_back(parseLines(childBlock, metadata, childIndent)); + metadata.ln -= 1; + } + else if (!cbe) + err("Did not expect indented child block!", out.metadata); + if (o.size() == 0 || o.back().type == TOKEN) { + o.push_back(out); + continue; + } + // This is a little complicated. Basically, the idea here is to build + // constructions like [if [< x 5] [a] [elif [< x 10] [b] [else [c]]]] + std::vector u; + u.push_back(o.back()); + if (bodiedContinued(o.back().val, out.val)) { + while (1) { + if (!bodiedContinued(u.back().val, out.val)) { + u.pop_back(); + break; + } + if (!u.back().args.size() + || !bodiedContinued(u.back().val, u.back().args.back().val)) { + break; + } + u.push_back(u.back().args.back()); + } + u.back().args.push_back(out); + while (u.size() > 1) { + Node v = u.back(); + u.pop_back(); + u.back().args.pop_back(); + u.back().args.push_back(v); + } + o.pop_back(); + o.push_back(u[0]); + } + else o.push_back(out); + } + if (o.size() == 1) + return o[0]; + else if (o.size()) + return astnode("seq", o, o[0].metadata); + else + return astnode("seq", o, Metadata()); +} + +// Parses serpent code +Node parseSerpent(std::string s) { + std::string input = s; + std::string file = "main"; + if (exists(s)) { + file = s; + input = get_file_contents(s); + } + return parseLines(splitLines(input), Metadata(file, 0, 0), 0); +} + + +using namespace std; diff --git a/libserpent/parser.h b/libserpent/parser.h new file mode 100644 index 000000000..e3632220a --- /dev/null +++ b/libserpent/parser.h @@ -0,0 +1,13 @@ +#ifndef ETHSERP_PARSER +#define ETHSERP_PARSER + +#include +#include +#include +#include +#include "util.h" + +// Serpent text -> parse tree +Node parseSerpent(std::string s); + +#endif diff --git a/libserpent/rewriter.cpp b/libserpent/rewriter.cpp new file mode 100644 index 000000000..eef9e9211 --- /dev/null +++ b/libserpent/rewriter.cpp @@ -0,0 +1,466 @@ +#include +#include +#include +#include +#include "util.h" +#include "lllparser.h" +#include "bignum.h" + +std::string valid[][3] = { + { "if", "2", "3" }, + { "unless", "2", "2" }, + { "while", "2", "2" }, + { "until", "2", "2" }, + { "code", "1", "2" }, + { "init", "2", "2" }, + { "shared", "2", "3" }, + { "alloc", "1", "1" }, + { "array", "1", "1" }, + { "call", "2", "4" }, + { "create", "1", "4" }, + { "msg", "4", "6" }, + { "getch", "2", "2" }, + { "setch", "3", "3" }, + { "sha3", "1", "2" }, + { "return", "1", "2" }, + { "inset", "1", "1" }, + { "import", "1", "1" }, + { "array_lit", "0", tt256 }, + { "seq", "0", tt256 }, + { "---END---", "", "" } //Keep this line at the end of the list +}; + +std::string macros[][2] = { + { + "(+= $a $b)", + "(set $a (+ $a $b))" + }, + { + "(*= $a $b)", + "(set $a (* $a $b))" + }, + { + "(-= $a $b)", + "(set $a (- $a $b))" + }, + { + "(/= $a $b)", + "(set $a (/ $a $b))" + }, + { + "(%= $a $b)", + "(set $a (% $a $b))" + }, + { + "(^= $a $b)", + "(set $a (^ $a $b))" + }, + { + "(@/= $a $b)", + "(set $a (@/ $a $b))" + }, + { + "(@%= $a $b)", + "(set $a (@% $a $b))" + }, + { + "(if $cond $do (else $else))", + "(if $cond $do $else)" + }, + { + "(code $code)", + "$code" + }, + { + "(access msg.data $ind)", + "(calldataload (mul 32 $ind))" + }, + { + "(array $len)", + "(alloc (mul 32 $len))" + }, + { + "(while $cond $do)", + "(until (not $cond) $do)", + }, + { + "(while (not $cond) $do)", + "(until $cond $do)", + }, + { + "(if $cond $do)", + "(unless (not $cond) $do)", + }, + { + "(if (not $cond) $do)", + "(unless $cond $do)", + }, + { + "(access contract.storage $ind)", + "(sload $ind)" + }, + { + "(access $var $ind)", + "(mload (add $var (mul 32 $ind)))" + }, + { + "(set (access contract.storage $ind) $val)", + "(sstore $ind $val)" + }, + { + "(set (access $var $ind) $val)", + "(mstore (add $var (mul 32 $ind)) $val)" + }, + { + "(getch $var $ind)", + "(mod (mload (add $var $ind)) 256)" + }, + { + "(setch $var $ind $val)", + "(mstore8 (add $var $ind) $val)", + }, + { + "(send $to $value)", + "(call (sub (gas) 25) $to $value 0 0 0 0)" + }, + { + "(send $gas $to $value)", + "(call $gas $to $value 0 0 0 0)" + }, + { + "(sha3 $x)", + "(seq (set $1 $x) (sha3 (ref $1) 32))" + }, + { + "(id $0)", + "$0" + }, + { + "(return $x)", + "(seq (set $1 $x) (~return (ref $1) 32))" + }, + { + "(return $start $len)", + "(~return $start (mul 32 $len))" + }, + { + "(&& $x $y)", + "(if $x $y 0)" + }, + { + "(|| $x $y)", + "(seq (set $1 $x) (if (get $1) (get $1) $y))" + }, + { + "(>= $x $y)", + "(not (slt $x $y))" + }, + { + "(<= $x $y)", + "(not (sgt $x $y))" + }, + { + "(@>= $x $y)", + "(not (lt $x $y))" + }, + { + "(@<= $x $y)", + "(not (gt $x $y))" + }, + { + "(create $code)", + "(create 0 $code)" + }, + { + "(create $endowment $code)", + "(seq (set $1 (msize)) (create $endowment (get $1) (lll (outer $code) (msize))))" + }, + { + "(call $f $dataval)", + "(msg (sub (gas) 45) $f 0 $dataval)" + }, + { + "(call $f $inp $inpsz)", + "(msg (sub (gas) 25) $f 0 $inp $inpsz)" + }, + { + "(call $f $inp $inpsz $outsz)", + "(seq (set $1 $outsz) (set $2 (alloc (mul 32 (get $1)))) (pop (call (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (ref $2) (mul 32 (get $1)))) (get $2))" + }, + { + "(msg $gas $to $val $inp $inpsz)", + "(seq (call $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))" + }, + { + "(msg $gas $to $val $dataval)", + "(seq (set $1 $dataval) (call $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))" + }, + { + "(msg $gas $to $val $inp $inpsz $outsz)", + "(seq (set $1 (mul 32 $outsz)) (set $2 (alloc (get $1))) (pop (call $gas $to $val $inp (mul 32 $inpsz) (ref $2) (get $1))) (get $2))" + }, + { + "(outer (init $init $code))", + "(seq $init (~return 0 (lll $code 0)))" + }, + { + "(outer (shared $shared (init $init (code $code))))", + "(seq $shared $init (~return 0 (lll (seq $shared $code) 0)))" + }, + { + "(outer $code)", + "(~return 0 (lll $code 0))" + }, + { + "(seq (seq) $x)", + "$x" + }, + { + "(inset $x)", + "$x" + }, + { + "(create $val (import $code))", + "(seq (set $1 (msize)) (create $val (get $1) (lll $code (get $1))))" + }, + { + "(create (import $x))", + "(seq (set $1 (msize)) (create $val (get $1) (lll $code (get $1))))" + }, + { + "(create $x)", + "(seq (set $1 (msize)) (create $val (get $1) (lll $code (get $1))))" + }, + { "msg.datasize", "(div (calldatasize) 32)" }, + { "msg.sender", "(caller)" }, + { "msg.value", "(callvalue)" }, + { "tx.gasprice", "(gasprice)" }, + { "tx.origin", "(origin)" }, + { "tx.gas", "(gas)" }, + { "contract.balance", "(balance)" }, + { "contract.address", "(address)" }, + { "block.prevhash", "(prevhash)" }, + { "block.coinbase", "(coinbase)" }, + { "block.timestamp", "(timestamp)" }, + { "block.number", "(number)" }, + { "block.difficulty", "(difficulty)" }, + { "block.gaslimit", "(gaslimit)" }, + { "stop", "(stop)" }, + { "---END---", "" } //Keep this line at the end of the list +}; + +std::vector > nodeMacros; + +std::string synonyms[][2] = { + { "|", "or" }, + { "or", "||" }, + { "&", "and" }, + { "and", "&&" }, + { "elif", "if" }, + { "!", "not" }, + { "string", "alloc" }, + { "+", "add" }, + { "-", "sub" }, + { "*", "mul" }, + { "/", "sdiv" }, + { "^", "exp" }, + { "**", "exp" }, + { "%", "smod" }, + { "@/", "div" }, + { "@%", "mod" }, + { "@<", "lt" }, + { "@>", "gt" }, + { "<", "slt" }, + { ">", "sgt" }, + { "=", "set" }, + { "==", "eq" }, + { "---END---", "" } //Keep this line at the end of the list +}; + +struct matchResult { + bool success; + std::map map; +}; + +// Returns two values. First, a boolean to determine whether the node matches +// the pattern, second, if the node does match then a map mapping variables +// in the pattern to nodes +matchResult match(Node p, Node n) { + matchResult o; + o.success = false; + if (p.type == TOKEN) { + if (p.val == n.val) o.success = true; + else if (p.val[0] == '$') { + o.success = true; + o.map[p.val.substr(1)] = n; + } + } + else if (n.type==TOKEN || p.val!=n.val || p.args.size()!=n.args.size()) { + } + else { + for (unsigned i = 0; i < p.args.size(); i++) { + matchResult oPrime = match(p.args[i], n.args[i]); + if (!oPrime.success) { + o.success = false; + return o; + } + for (std::map::iterator it = oPrime.map.begin(); + it != oPrime.map.end(); + it++) { + o.map[(*it).first] = (*it).second; + } + } + o.success = true; + } + return o; +} + +// Fills in the pattern with a dictionary mapping variable names to +// nodes (these dicts are generated by match). Match and subst together +// create a full pattern-matching engine. +Node subst(Node pattern, + std::map dict, + std::string varflag, + Metadata metadata) { + if (pattern.type == TOKEN && pattern.val[0] == '$') { + if (dict.count(pattern.val.substr(1))) { + return dict[pattern.val.substr(1)]; + } + else { + return token(varflag + pattern.val.substr(1), metadata); + } + } + else if (pattern.type == TOKEN) { + return pattern; + } + else { + std::vector args; + for (unsigned i = 0; i < pattern.args.size(); i++) { + args.push_back(subst(pattern.args[i], dict, varflag, metadata)); + } + return astnode(pattern.val, args, metadata); + } +} + +// Recursively applies rewrite rules +Node apply_rules(Node node) { + // If the rewrite rules have not yet been parsed, parse them + if (!nodeMacros.size()) { + for (int i = 0; i < 9999; i++) { + std::vector o; + if (macros[i][0] == "---END---") break; + o.push_back(parseLLL(macros[i][0])); + o.push_back(parseLLL(macros[i][1])); + nodeMacros.push_back(o); + } + } + // Main code + unsigned pos = 0; + std::string prefix = "_temp"+mkUniqueToken()+"_"; + while(1) { + if (synonyms[pos][0] == "---END---") { + break; + } + else if (node.type == ASTNODE && node.val == synonyms[pos][0]) { + node.val = synonyms[pos][1]; + } + pos++; + } + for (pos = 0; pos < nodeMacros.size(); pos++) { + Node pattern = nodeMacros[pos][0]; + matchResult mr = match(pattern, node); + if (mr.success) { + Node pattern2 = nodeMacros[pos][1]; + node = subst(pattern2, mr.map, prefix, node.metadata); + } + } + if (node.type == ASTNODE && node.val != "ref" && node.val != "get") { + unsigned i = 0; + if (node.val == "set") i = 1; + for (i = i; i < node.args.size(); i++) { + node.args[i] = apply_rules(node.args[i]); + } + } + else if (node.type == TOKEN && !isNumberLike(node)) { + std::vector args; + args.push_back(node); + node = astnode("get", args, node.metadata); + } + // This allows people to use ~x as a way of having functions with the same + // name and arity as macros; the idea is that ~x is a "final" form, and + // should not be remacroed, but it is converted back at the end + if (node.type == ASTNODE && node.val[0] == '~') + node.val = node.val.substr(1); + return node; +} + +Node optimize(Node inp) { + if (inp.type == TOKEN) return tryNumberize(inp); + for (unsigned i = 0; i < inp.args.size(); i++) { + inp.args[i] = optimize(inp.args[i]); + } + if (inp.args.size() == 2 + && inp.args[0].type == TOKEN + && inp.args[1].type == TOKEN) { + std::string o; + if (inp.val == "add") { + o = decimalMod(decimalAdd(inp.args[0].val, inp.args[1].val), tt256); + } + else if (inp.val == "sub") { + if (decimalGt(inp.args[0].val, inp.args[1].val, true)) + o = decimalSub(inp.args[0].val, inp.args[1].val); + } + else if (inp.val == "mul") { + o = decimalMod(decimalMul(inp.args[0].val, inp.args[1].val), tt256); + } + else if (inp.val == "div" && inp.args[1].val != "0") { + o = decimalDiv(inp.args[0].val, inp.args[1].val); + } + else if (inp.val == "sdiv" && inp.args[1].val != "0" + && decimalGt(tt255, inp.args[0].val) + && decimalGt(tt255, inp.args[1].val)) { + o = decimalDiv(inp.args[0].val, inp.args[1].val); + } + else if (inp.val == "mod" && inp.args[1].val != "0") { + o = decimalMod(inp.args[0].val, inp.args[1].val); + } + else if (inp.val == "smod" && inp.args[1].val != "0" + && decimalGt(tt255, inp.args[0].val) + && decimalGt(tt255, inp.args[1].val)) { + o = decimalMod(inp.args[0].val, inp.args[1].val); + } + if (o.length()) return token(o, inp.metadata); + } + return inp; +} + +Node validate(Node inp) { + if (inp.type == ASTNODE) { + int i = 0; + while(valid[i][0] != "---END---") { + if (inp.val == valid[i][0]) { + if (decimalGt(valid[i][1], intToDecimal(inp.args.size()))) { + err("Too few arguments for "+inp.val, inp.metadata); + } + if (decimalGt(intToDecimal(inp.args.size()), valid[i][2])) { + err("Too many arguments for "+inp.val, inp.metadata); + } + } + i++; + } + } + for (unsigned i = 0; i < inp.args.size(); i++) validate(inp.args[i]); + return inp; +} + +Node preprocess(Node inp) { + std::vector args; + args.push_back(inp); + return astnode("outer", args, inp.metadata); +} + +Node rewrite(Node inp) { + return optimize(apply_rules(validate(preprocess(inp)))); +} + +using namespace std; diff --git a/libserpent/rewriter.h b/libserpent/rewriter.h new file mode 100644 index 000000000..b2e8f00dd --- /dev/null +++ b/libserpent/rewriter.h @@ -0,0 +1,13 @@ +#ifndef ETHSERP_REWRITER +#define ETHSERP_REWRITER + +#include +#include +#include +#include +#include "util.h" + +// Applies rewrite rules +Node rewrite(Node inp); + +#endif diff --git a/libserpent/tokenize.cpp b/libserpent/tokenize.cpp new file mode 100644 index 000000000..0fc3fb2fa --- /dev/null +++ b/libserpent/tokenize.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include "util.h" + +// These appear as independent tokens even if inside a stream of symbols +const std::string atoms[] = { "#", "//", "(", ")", "[", "]", "{", "}" }; +const int numAtoms = 8; + +// Is the char alphanumeric, a space, a bracket, a quote, a symbol? +int chartype(char c) { + if (c >= '0' && c <= '9') return ALPHANUM; + else if (c >= 'a' && c <= 'z') return ALPHANUM; + else if (c >= 'A' && c <= 'Z') return ALPHANUM; + else if (std::string("~._$").find(c) != std::string::npos) return ALPHANUM; + else if (c == '\t' || c == ' ' || c == '\n') return SPACE; + else if (std::string("()[]{}").find(c) != std::string::npos) return BRACK; + else if (c == '"') return DQUOTE; + else if (c == '\'') return SQUOTE; + else return SYMB; +} + +// "y = f(45,124)/3" -> [ "y", "f", "(", "45", ",", "124", ")", "/", "3"] +std::vector tokenize(std::string inp, Metadata metadata) { + int curtype = SPACE; + unsigned pos = 0; + int lastNewline = 0; + metadata.ch = 0; + std::string cur; + std::vector out; + + inp += " "; + while (pos < inp.length()) { + int headtype = chartype(inp[pos]); + // Are we inside a quote? + if (curtype == SQUOTE || curtype == DQUOTE) { + // Close quote + if (headtype == curtype) { + cur += inp[pos]; + out.push_back(token(cur, metadata)); + cur = ""; + metadata.ch = pos - lastNewline; + curtype = SPACE; + pos += 1; + } + // eg. \xc3 + else if (inp.length() >= pos + 4 && inp.substr(pos, 2) == "\\x") { + cur += (std::string("0123456789abcdef").find(inp[pos+2]) * 16 + + std::string("0123456789abcdef").find(inp[pos+3])); + pos += 4; + } + // Newline + else if (inp.substr(pos, 2) == "\\n") { + cur += '\n'; + pos += 2; + } + // Backslash escape + else if (inp.length() >= pos + 2 && inp[pos] == '\\') { + cur += inp[pos + 1]; + pos += 2; + } + // Normal character + else { + cur += inp[pos]; + pos += 1; + } + } + else { + // Handle atoms ( '//', '#', brackets ) + for (int i = 0; i < numAtoms; i++) { + int split = cur.length() - atoms[i].length(); + if (split >= 0 && cur.substr(split) == atoms[i]) { + if (split > 0) { + out.push_back(token(cur.substr(0, split), metadata)); + } + metadata.ch += split; + out.push_back(token(cur.substr(split), metadata)); + metadata.ch = pos - lastNewline; + cur = ""; + curtype = SPACE; + } + } + // Special case the minus sign + if (cur.length() > 1 && cur[cur.length() - 1] == '-') { + out.push_back(token(cur.substr(0, cur.length() - 1), metadata)); + out.push_back(token("-", metadata)); + cur = ""; + } + // Boundary between different char types + if (headtype != curtype) { + if (curtype != SPACE && cur != "") { + out.push_back(token(cur, metadata)); + } + metadata.ch = pos - lastNewline; + cur = ""; + } + cur += inp[pos]; + curtype = headtype; + pos += 1; + } + if (inp[pos] == '\n') { + lastNewline = pos; + metadata.ch = 0; + metadata.ln += 1; + } + } + return out; +} + + diff --git a/libserpent/tokenize.h b/libserpent/tokenize.h new file mode 100644 index 000000000..7ded48cc5 --- /dev/null +++ b/libserpent/tokenize.h @@ -0,0 +1,14 @@ +#ifndef ETHSERP_TOKENIZE +#define ETHSERP_TOKENIZE + +#include +#include +#include +#include +#include "util.h" + +int chartype(char c); + +std::vector tokenize(std::string inp, Metadata meta=Metadata()); + +#endif diff --git a/libserpent/util.cpp b/libserpent/util.cpp new file mode 100644 index 000000000..6ca39de9d --- /dev/null +++ b/libserpent/util.cpp @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include "util.h" +#include "bignum.h" +#include +#include + +//Token or value node constructor +Node token(std::string val, Metadata met) { + Node o; + o.type = 0; + o.val = val; + o.metadata = met; + return o; +} + +//AST node constructor +Node astnode(std::string val, std::vector args, Metadata met) { + Node o; + o.type = 1; + o.val = val; + o.args = args; + o.metadata = met; + return o; +} + +// Print token list +std::string printTokens(std::vector tokens) { + std::string s = ""; + for (unsigned i = 0; i < tokens.size(); i++) { + s += tokens[i].val + " "; + } + return s; +} + +// Prints a lisp AST on one line +std::string printSimple(Node ast) { + if (ast.type == TOKEN) return ast.val; + std::string o = "(" + ast.val; + std::vector subs; + for (unsigned i = 0; i < ast.args.size(); i++) { + o += " " + printSimple(ast.args[i]); + } + return o + ")"; +} + +// Number of tokens in a tree +int treeSize(Node prog) { + if (prog.type == TOKEN) return 1; + int o = 0; + for (unsigned i = 0; i < prog.args.size(); i++) o += treeSize(prog.args[i]); + return o; +} + +// Pretty-prints a lisp AST +std::string printAST(Node ast, bool printMetadata) { + if (ast.type == TOKEN) return ast.val; + std::string o = "("; + if (printMetadata) { + o += ast.metadata.file + " "; + o += intToDecimal(ast.metadata.ln) + " "; + o += intToDecimal(ast.metadata.ch) + ": "; + } + o += ast.val; + std::vector subs; + for (unsigned i = 0; i < ast.args.size(); i++) { + subs.push_back(printAST(ast.args[i], printMetadata)); + } + unsigned k = 0; + std::string out = " "; + // As many arguments as possible go on the same line as the function, + // except when seq is used + while (k < subs.size() && o != "(seq") { + if (subs[k].find("\n") != std::string::npos || (out + subs[k]).length() >= 80) break; + out += subs[k] + " "; + k += 1; + } + // All remaining arguments go on their own lines + if (k < subs.size()) { + o += out + "\n"; + std::vector subsSliceK; + for (unsigned i = k; i < subs.size(); i++) subsSliceK.push_back(subs[i]); + o += indentLines(joinLines(subsSliceK)); + o += "\n)"; + } + else { + o += out.substr(0, out.size() - 1) + ")"; + } + return o; +} + +// Splits text by line +std::vector splitLines(std::string s) { + unsigned pos = 0; + int lastNewline = 0; + std::vector o; + while (pos < s.length()) { + if (s[pos] == '\n') { + o.push_back(s.substr(lastNewline, pos - lastNewline)); + lastNewline = pos + 1; + } + pos = pos + 1; + } + o.push_back(s.substr(lastNewline)); + return o; +} + +// Inverse of splitLines +std::string joinLines(std::vector lines) { + std::string o = "\n"; + for (unsigned i = 0; i < lines.size(); i++) { + o += lines[i] + "\n"; + } + return o.substr(1, o.length() - 2); +} + +// Indent all lines by 4 spaces +std::string indentLines(std::string inp) { + std::vector lines = splitLines(inp); + for (unsigned i = 0; i < lines.size(); i++) lines[i] = " "+lines[i]; + return joinLines(lines); +} + +// Converts string to simple numeric format +std::string strToNumeric(std::string inp) { + std::string o = "0"; + if (inp == "") { + o = ""; + } + else if ((inp[0] == '"' && inp[inp.length()-1] == '"') + || (inp[0] == '\'' && inp[inp.length()-1] == '\'')) { + for (unsigned i = 1; i < inp.length() - 1; i++) { + o = decimalAdd(decimalMul(o,"256"), intToDecimal(inp[i])); + } + } + else if (inp.substr(0,2) == "0x") { + for (unsigned i = 2; i < inp.length(); i++) { + int dig = std::string("0123456789abcdef").find(inp[i]); + if (dig < 0) return ""; + o = decimalAdd(decimalMul(o,"16"), intToDecimal(dig)); + } + } + else { + bool isPureNum = true; + for (unsigned i = 0; i < inp.length(); i++) { + isPureNum = isPureNum && inp[i] >= '0' && inp[i] <= '9'; + } + o = isPureNum ? inp : ""; + } + return o; +} + +// Does the node contain a number (eg. 124, 0xf012c, "george") +bool isNumberLike(Node node) { + if (node.type == ASTNODE) return false; + return strToNumeric(node.val) != ""; +} + +//Normalizes number representations +Node nodeToNumeric(Node node) { + std::string o = strToNumeric(node.val); + return token(o == "" ? node.val : o, node.metadata); +} + +Node tryNumberize(Node node) { + if (node.type == TOKEN && isNumberLike(node)) return nodeToNumeric(node); + return node; +} + +//Converts a value to an array of byte number nodes +std::vector toByteArr(std::string val, Metadata metadata, int minLen) { + std::vector o; + int L = 0; + while (val != "0" || L < minLen) { + o.push_back(token(decimalMod(val, "256"), metadata)); + val = decimalDiv(val, "256"); + L++; + } + std::vector o2; + for (int i = o.size() - 1; i >= 0; i--) o2.push_back(o[i]); + return o2; +} + +int counter = 0; + +//Makes a unique token +std::string mkUniqueToken() { + counter++; + return intToDecimal(counter); +} + +//Does a file exist? http://stackoverflow.com/questions/12774207 +bool exists(std::string fileName) { + std::ifstream infile(fileName.c_str()); + return infile.good(); +} + +//Reads a file: http://stackoverflow.com/questions/2602013 +std::string get_file_contents(std::string filename) +{ + std::ifstream in(filename.c_str(), std::ios::in | std::ios::binary); + if (in) + { + std::string contents; + in.seekg(0, std::ios::end); + contents.resize(in.tellg()); + in.seekg(0, std::ios::beg); + in.read(&contents[0], contents.size()); + in.close(); + return(contents); + } + throw(errno); +} + +//Report error +void err(std::string errtext, Metadata met) { + std::string err = "Error (file \"" + met.file + "\", line " + + intToDecimal(met.ln) + ", char " + intToDecimal(met.ch) + + "): " + errtext; + std::cerr << err << "\n"; + throw(err); +} + +//Bin to hex +std::string binToHex(std::string inp) { + std::string o = ""; + for (unsigned i = 0; i < inp.length(); i++) { + unsigned char v = inp[i]; + o += std::string("0123456789abcdef").substr(v/16, 1) + + std::string("0123456789abcdef").substr(v%16, 1); + } + return o; +} + +//Hex to bin +std::string hexToBin(std::string inp) { + std::string o = ""; + for (unsigned i = 0; i+1 < inp.length(); i+=2) { + char v = (char)(std::string("0123456789abcdef").find(inp[i]) * 16 + + std::string("0123456789abcdef").find(inp[i+1])); + o += v; + } + return o; +} + +//Lower to upper +std::string upperCase(std::string inp) { + std::string o = ""; + for (unsigned i = 0; i < inp.length(); i++) { + if (inp[i] >= 97 && inp[i] <= 122) o += inp[i] - 32; + else o += inp[i]; + } + return o; +} diff --git a/libserpent/util.h b/libserpent/util.h new file mode 100644 index 000000000..a593d7451 --- /dev/null +++ b/libserpent/util.h @@ -0,0 +1,106 @@ +#ifndef ETHSERP_UTIL +#define ETHSERP_UTIL + +#include +#include +#include +#include +#include +#include + +const int TOKEN = 0, + ASTNODE = 1, + SPACE = 2, + BRACK = 3, + SQUOTE = 4, + DQUOTE = 5, + SYMB = 6, + ALPHANUM = 7, + LPAREN = 8, + RPAREN = 9, + COMMA = 10, + COLON = 11, + UNARY_OP = 12, + BINARY_OP = 13, + COMPOUND = 14; + +// Stores metadata about each token +class Metadata { + public: + Metadata(std::string File="main", int Ln=0, int Ch=0) { + file = File; + ln = Ln; + ch = Ch; + } + std::string file; + int ln; + int ch; +}; + +std::string mkUniqueToken(); + +// type can be TOKEN or ASTNODE +struct Node { + int type; + std::string val; + std::vector args; + Metadata metadata; +}; +Node token(std::string val, Metadata met=Metadata()); +Node astnode(std::string val, std::vector args, Metadata met=Metadata()); + +// Number of tokens in a tree +int treeSize(Node prog); + +// Print token list +std::string printTokens(std::vector tokens); + +// Prints a lisp AST on one line +std::string printSimple(Node ast); + +// Pretty-prints a lisp AST +std::string printAST(Node ast, bool printMetadata=false); + +// Splits text by line +std::vector splitLines(std::string s); + +// Inverse of splitLines +std::string joinLines(std::vector lines); + +// Indent all lines by 4 spaces +std::string indentLines(std::string inp); + +// Converts string to simple numeric format +std::string strToNumeric(std::string inp); + +// Does the node contain a number (eg. 124, 0xf012c, "george") +bool isNumberLike(Node node); + +//Normalizes number representations +Node nodeToNumeric(Node node); + +//If a node is numeric, normalize its representation +Node tryNumberize(Node node); + +//Converts a value to an array of byte number nodes +std::vector toByteArr(std::string val, Metadata metadata, int minLen=1); + +//Reads a file +std::string get_file_contents(std::string filename); + +//Does a file exist? +bool exists(std::string fileName); + +//Report error +void err(std::string errtext, Metadata met); + +//Bin to hex +std::string binToHex(std::string inp); + +//Hex to bin +std::string hexToBin(std::string inp); + +//Lower to upper +std::string upperCase(std::string inp); + +#endif diff --git a/lllc/CMakeLists.txt b/lllc/CMakeLists.txt index ff5d672d0..1188f1b5b 100644 --- a/lllc/CMakeLists.txt +++ b/lllc/CMakeLists.txt @@ -3,9 +3,6 @@ cmake_policy(SET CMP0015 NEW) aux_source_directory(. SRC_LIST) include_directories(..) -#link_directories(../libethsupport) -#link_directories(../libethcore) -#link_directories(../liblll) set(EXECUTABLE lllc) @@ -47,7 +44,6 @@ endif () target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} ethsupport) target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) target_link_libraries(${EXECUTABLE} gmp) diff --git a/lllc/main.cpp b/lllc/main.cpp index 020d137bb..22d40d2da 100644 --- a/lllc/main.cpp +++ b/lllc/main.cpp @@ -23,9 +23,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "BuildInfo.h" using namespace std; using namespace eth; diff --git a/neth/main.cpp b/neth/main.cpp index d82ca4625..a350a9d75 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -26,8 +26,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/test/MemTrie.cpp b/test/MemTrie.cpp index d7f4e7d02..5c819ffbd 100644 --- a/test/MemTrie.cpp +++ b/test/MemTrie.cpp @@ -21,7 +21,8 @@ #include "MemTrie.h" -#include +#include +#include #include using namespace std; using namespace eth; diff --git a/test/MemTrie.h b/test/MemTrie.h index 7a9237592..8c90f2f3f 100644 --- a/test/MemTrie.h +++ b/test/MemTrie.h @@ -21,8 +21,8 @@ #pragma once -#include -#include +#include +#include namespace eth { diff --git a/test/TrieHash.cpp b/test/TrieHash.cpp index f6b730140..8f4161a17 100644 --- a/test/TrieHash.cpp +++ b/test/TrieHash.cpp @@ -21,7 +21,8 @@ #include "TrieHash.h" -#include +#include +#include #include using namespace std; using namespace eth; diff --git a/test/TrieHash.h b/test/TrieHash.h index f226f2d75..391c42633 100644 --- a/test/TrieHash.h +++ b/test/TrieHash.h @@ -21,8 +21,8 @@ #pragma once -#include -#include +#include +#include namespace eth { diff --git a/test/crypto.cpp b/test/crypto.cpp index 53be1db15..c39de78d7 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -22,9 +22,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/test/dagger.cpp b/test/dagger.cpp index 27ad1c741..4f65b47aa 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -21,7 +21,7 @@ */ #include -#include +#include #include using namespace std; using namespace std::chrono; diff --git a/test/hexPrefix.cpp b/test/hexPrefix.cpp index 871e86f09..5ea670923 100644 --- a/test/hexPrefix.cpp +++ b/test/hexPrefix.cpp @@ -22,8 +22,8 @@ #include #include "JsonSpiritHeaders.h" -#include -#include +#include +#include #include using namespace std; diff --git a/test/main.cpp b/test/main.cpp index b85f00b03..1497f2981 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -20,7 +20,7 @@ * Main test functions. */ -#include +#include #include "TrieHash.h" #include "MemTrie.h" @@ -35,7 +35,7 @@ int vmTest(); int hexPrefixTest(); int peerTest(int argc, char** argv); -#include +#include #include using namespace std; using namespace eth; diff --git a/test/rlp.cpp b/test/rlp.cpp index 0a62df9e3..548be8d9b 100644 --- a/test/rlp.cpp +++ b/test/rlp.cpp @@ -23,9 +23,9 @@ #include #include #include "JsonSpiritHeaders.h" -#include -#include -#include +#include +#include +#include #include #include diff --git a/test/trie.cpp b/test/trie.cpp index 12d2c2e3f..1ba698333 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -23,7 +23,7 @@ #include #include #include "JsonSpiritHeaders.h" -#include +#include #include "TrieHash.h" #include "MemTrie.h" #include diff --git a/test/vm.cpp b/test/vm.cpp index f59704178..1d5c630fe 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -470,7 +470,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) BOOST_AUTO_TEST_CASE(vm_tests) { // Populate tests first: - try + /*try { cnote << "Populating VM tests..."; json_spirit::mValue v; @@ -483,7 +483,7 @@ BOOST_AUTO_TEST_CASE(vm_tests) catch (std::exception const& e) { BOOST_ERROR("Failed VM Test with Exception: " << e.what()); - } + }*/ try { diff --git a/walleth/MainWin.cpp b/walleth/MainWin.cpp index 6500822dd..cbd16c298 100644 --- a/walleth/MainWin.cpp +++ b/walleth/MainWin.cpp @@ -7,9 +7,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include "BuildInfo.h"