From f550217449aed43a242173f9429406ab833330c6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 27 Jul 2014 13:09:36 +0200 Subject: [PATCH] Updates to assembler - see the sub-codes. --- eth/main.cpp | 13 +++- libethential/FixedHash.cpp | 3 + libethential/FixedHash.h | 6 +- libethential/Log.h | 2 +- libethereum/Client.cpp | 26 ++++---- libethereum/Client.h | 6 ++ liblll/Assembly.cpp | 74 +++++++++++++++++---- liblll/Assembly.h | 12 ++-- liblll/CodeFragment.cpp | 13 +--- liblll/CodeFragment.h | 8 +-- liblll/Compiler.cpp | 9 +-- neth/main.cpp | 6 +- stdserv.js | 130 +++++++++++++++++++++++++++++++++++++ 13 files changed, 242 insertions(+), 66 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index cc845cf3f..dbb0234ce 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -169,7 +169,7 @@ string pretty(h160 _a, eth::State _st) } return ns; } -bytes parse_data(string _args); +bytes parseData(string _args); int main(int argc, char** argv) { unsigned short listenPort = 30303; @@ -309,9 +309,16 @@ int main(int argc, char** argv) if (interactive) { + string logbuf; string l; while (true) { + g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << "Press Enter" << flush; }; + cout << logbuf << "Press Enter" << flush; + std::getline(cin, l); + logbuf.clear(); + g_logPost = [&](std::string const& a, char const*) { logbuf += a + "\n"; }; + #if ETH_READLINE if (l.size()) add_history(l.c_str()); @@ -434,7 +441,7 @@ int main(int argc, char** argv) cnote << "Data:"; cnote << sdata; - bytes data = parse_data(sdata); + bytes data = parseData(sdata); cnote << "Bytes:"; string sbd = asString(data); bytes bbd = asBytes(sbd); @@ -695,7 +702,7 @@ int main(int argc, char** argv) return 0; } -bytes parse_data(string _args) +bytes parseData(string _args) { bytes m_data; stringstream args(_args); diff --git a/libethential/FixedHash.cpp b/libethential/FixedHash.cpp index 9d16cacb2..885d593e5 100644 --- a/libethential/FixedHash.cpp +++ b/libethential/FixedHash.cpp @@ -19,7 +19,10 @@ * @date 2014 */ +#include #include "FixedHash.h" using namespace std; using namespace eth; + +std::mt19937_64 eth::s_fixedHashEngine(time(0)); diff --git a/libethential/FixedHash.h b/libethential/FixedHash.h index 07e257534..2e3a92ce4 100644 --- a/libethential/FixedHash.h +++ b/libethential/FixedHash.h @@ -31,6 +31,8 @@ namespace eth { +extern std::mt19937_64 s_fixedHashEngine; + /// Fixed-size raw-byte array container type, with an API optimised for storing hashes. /// Transparently converts to/from the corresponding arithmetic type; this will /// assume the data contained in the hash is big-endian. @@ -125,7 +127,7 @@ public: /// @returns a randomly-valued hash template - static FixedHash random(Engine& _eng) + static FixedHash random(Engine& _eng = s_fixedHashEngine) { FixedHash ret; for (auto& i: ret.m_data) @@ -154,12 +156,10 @@ public: return ret; } - private: std::array m_data; ///< The binary data. }; - /// Fast equality operator for h256. template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const { diff --git a/libethential/Log.h b/libethential/Log.h index ea7a06233..77a84333c 100644 --- a/libethential/Log.h +++ b/libethential/Log.h @@ -39,7 +39,7 @@ public: }; /// A simple log-output function that prints log messages to stdout. -void simpleDebugOut(std::string const&, char const* ); +void simpleDebugOut(std::string const&, char const*); /// The logging system's current verbosity. extern int g_logVerbosity; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 37512d429..841ef00ad 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -307,7 +307,7 @@ void Client::inject(bytesConstRef _rlp) void Client::work(bool _justQueue) { - cdebug << ">>> WORK"; + cworkin << "WORK"; h256Set changeds; // Process network events. @@ -317,14 +317,14 @@ void Client::work(bool _justQueue) Guard l(x_net); if (m_net && !_justQueue) { - cdebug << "--- WORK: NETWORK"; + cwork << "NETWORK"; m_net->process(); // must be in guard for now since it uses the blockchain. // returns h256Set as block hashes, once for each block that has come in/gone out. - cdebug << "--- WORK: NET <==> TQ ; CHAIN ==> NET ==> BQ"; + cwork << "NET <==> TQ ; CHAIN ==> NET ==> BQ"; m_net->sync(m_tq, m_bq); - cdebug << "--- TQ:" << m_tq.items() << "; BQ:" << m_bq.items(); + cwork << "TQ:" << m_tq.items() << "; BQ:" << m_bq.items(); } } @@ -361,7 +361,7 @@ void Client::work(bool _justQueue) if (m_doMine) { - cdebug << "--- WORK: MINE"; + cwork << "MINE"; m_restartMining = false; // Mine for a while. @@ -377,9 +377,9 @@ void Client::work(bool _justQueue) if (mineInfo.completed) { // Import block. - cdebug << "--- WORK: COMPLETE MINE%"; + cwork << "COMPLETE MINE"; m_postMine.completeMine(); - cdebug << "--- WORK: CHAIN <== postSTATE"; + cwork << "CHAIN <== postSTATE"; h256s hs = m_bc.attemptImport(m_postMine.blockData(), m_stateDB); if (hs.size()) { @@ -392,7 +392,7 @@ void Client::work(bool _justQueue) } else { - cdebug << "--- WORK: SLEEP"; + cwork << "SLEEP"; this_thread::sleep_for(chrono::milliseconds(100)); } } @@ -407,7 +407,7 @@ void Client::work(bool _justQueue) { ClientGuard l(this); - cdebug << "--- WORK: BQ ==> CHAIN ==> STATE"; + cwork << "BQ ==> CHAIN ==> STATE"; OverlayDB db = m_stateDB; m_lock.unlock(); h256s newBlocks = m_bc.sync(m_bq, db, 100); @@ -421,7 +421,7 @@ void Client::work(bool _justQueue) if (newBlocks.size()) m_stateDB = db; - cdebug << "--- WORK: preSTATE <== CHAIN"; + cwork << "preSTATE <== CHAIN"; if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address()) { if (m_doMine) @@ -432,7 +432,7 @@ void Client::work(bool _justQueue) } // returns h256s as blooms, once for each transaction. - cdebug << "--- WORK: postSTATE <== TQ"; + cwork << "postSTATE <== TQ"; h256s newPendingBlooms = m_postMine.sync(m_tq); if (newPendingBlooms.size()) { @@ -446,9 +446,9 @@ void Client::work(bool _justQueue) } } - cdebug << "--- WORK: noteChanged" << changeds.size() << "items"; + cwork << "noteChanged" << changeds.size() << "items"; noteChanged(changeds); - cdebug << "<<< WORK"; + cworkout << "WORK"; } void Client::lock() const diff --git a/libethereum/Client.h b/libethereum/Client.h index 62b1b4fcf..ee0bd145a 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -159,6 +159,12 @@ struct Watch struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 6; }; #define cwatch eth::LogOutputStream() +struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 5; }; +struct WorkOutChannel: public LogChannel { static const char* name() { return "() +#define cworkin eth::LogOutputStream() +#define cworkout eth::LogOutputStream() /** * @brief Main API hub for interfacing with Ethereum. diff --git a/liblll/Assembly.cpp b/liblll/Assembly.cpp index 3abdf66f7..78552f3c5 100644 --- a/liblll/Assembly.cpp +++ b/liblll/Assembly.cpp @@ -32,7 +32,7 @@ int AssemblyItem::deposit() const { case Operation: return c_instructionInfo.at((Instruction)(byte)m_data).ret - c_instructionInfo.at((Instruction)(byte)m_data).args; - case Push: case PushString: case PushTag: case PushData: + case Push: case PushString: case PushTag: case PushData: case PushSub: case PushSubSize: return 1; case Tag: return 0; @@ -61,8 +61,12 @@ unsigned Assembly::bytesRequired() const case Push: ret += 1 + max(1, eth::bytesRequired(i.m_data)); break; + case PushSubSize: + ret += 4; // worst case: a 16MB program + break; case PushTag: case PushData: + case PushSub: ret += 1 + br; case Tag:; default:; @@ -87,6 +91,8 @@ void Assembly::append(Assembly const& _a) m_data.insert(i); for (auto const& i: _a.m_strings) m_strings.insert(i); + for (auto const& i: _a.m_subs) + m_subs.insert(i); assert(!_a.m_baseDeposit); assert(!_a.m_totalDeposit); @@ -127,6 +133,12 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) case PushData: _out << " PUSH*[" << hex << (unsigned)i.data() << "]"; break; + case PushSub: + _out << " PUSHs[" << hex << h256(i.data()).abridged() << "]"; + break; + case PushSubSize: + _out << " PUSHss[" << hex << h256(i.data()).abridged() << "]"; + break; case UndefinedItem: _out << " ???"; default:; @@ -134,38 +146,50 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) return _out; } -ostream& Assembly::streamOut(ostream& _out) const +ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const { - _out << ".code:" << endl; + _out << _prefix << ".code:" << endl; for (AssemblyItem const& i: m_items) switch (i.m_type) { case Operation: - _out << " " << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; + _out << _prefix << " " << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; break; case Push: - _out << " PUSH " << i.m_data << endl; + _out << _prefix << " PUSH " << i.m_data << endl; break; case PushString: - _out << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; + _out << _prefix << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; break; case PushTag: - _out << " PUSH [tag" << i.m_data << "]" << endl; + _out << _prefix << " PUSH [tag" << i.m_data << "]" << endl; + break; + case PushSub: + _out << _prefix << " PUSH [$" << h256(i.m_data).abridged() << "]" << endl; + break; + case PushSubSize: + _out << _prefix << " PUSH #[$" << h256(i.m_data).abridged() << "]" << endl; break; case Tag: - _out << "tag" << i.m_data << ": " << endl; + _out << _prefix << "tag" << i.m_data << ": " << endl; break; case PushData: - _out << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; + _out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; break; default:; } - if (m_data.size()) + if (m_data.size() || m_subs.size()) { - _out << ".data:" << endl; + _out << _prefix << ".data:" << endl; for (auto const& i: m_data) - _out << " " << hex << (unsigned)(u256)i.first << ": " << toHex(i.second) << endl; + if (!m_subs.count(i.first)) + _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << toHex(i.second) << endl; + for (auto const& i: m_subs) + { + _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << endl; + i.second.streamOut(_out, _prefix + " "); + } } return _out; } @@ -195,8 +219,10 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; #define copt eth::LogOutputStream() -void Assembly::optimise() +Assembly& Assembly::optimise(bool _enable) { + if (!_enable) + return *this; map> c_simple = { { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, @@ -221,6 +247,8 @@ void Assembly::optimise() { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushTag, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushString, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { PushSub, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { PushSubSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } }, { { Instruction::NOT, Instruction::NOT }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, }; @@ -309,6 +337,11 @@ void Assembly::optimise() } copt << total << " optimisations done."; + + for (auto& i: m_subs) + i.second.optimise(true); + + return *this; } bytes Assembly::assemble() const @@ -323,6 +356,9 @@ bytes Assembly::assemble() const unsigned bytesPerTag = eth::bytesRequired(totalBytes); byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; + for (auto const& i: m_subs) + m_data[i.first] = i.second.assemble(); + for (AssemblyItem const& i: m_items) switch (i.m_type) { @@ -358,13 +394,23 @@ bytes Assembly::assemble() const ret.resize(ret.size() + bytesPerTag); break; } - case PushData: + case PushData: case PushSub: { ret.push_back(tagPush); dataRef.insert(make_pair((h256)i.m_data, ret.size())); ret.resize(ret.size() + bytesPerTag); break; } + case PushSubSize: + { + auto s = m_data[i.m_data].size(); + byte b = max(1, eth::bytesRequired(s)); + ret.push_back((byte)Instruction::PUSH1 - 1 + b); + ret.resize(ret.size() + b); + bytesRef byr(&ret.back() + 1 - b, b); + toBigEndian(s, byr); + break; + } case Tag: tagPos[(unsigned)i.m_data] = ret.size(); break; diff --git a/liblll/Assembly.h b/liblll/Assembly.h index 4a6d02ce0..581e16433 100644 --- a/liblll/Assembly.h +++ b/liblll/Assembly.h @@ -30,7 +30,7 @@ namespace eth { -enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, Tag, PushData }; +enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, Tag, PushData }; class Assembly; @@ -70,7 +70,9 @@ public: AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { h256 h = (u256)std::hash()(asString(_data)); m_data[h] = _data; return AssemblyItem(PushData, h); } + AssemblyItem newSub(Assembly const& _sub) { h256 h = h256::random(s_fixedHashEngine); m_subs[h] = _sub; return AssemblyItem(PushSub, h); } AssemblyItem newPushString(std::string const& _data) { h256 h = (u256)std::hash()(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } + AssemblyItem newPushSubSize(h256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem append() { return append(newTag()); } void append(Assembly const& _a); @@ -78,6 +80,7 @@ public: AssemblyItem const& append(AssemblyItem const& _i); AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } + AssemblyItem appendSubSize(Assembly const& _asm) { auto ret = newSub(_asm); append(newPushSubSize(ret.data())); return ret; } AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } @@ -102,8 +105,8 @@ public: std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } int deposit() const { return m_deposit; } bytes assemble() const; - void optimise(); - std::ostream& streamOut(std::ostream& _out) const; + Assembly& optimise(bool _enable); + std::ostream& streamOut(std::ostream& _out, std::string const& _prefix = "") const; private: void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) throw InvalidDeposit(); } @@ -111,7 +114,8 @@ private: unsigned m_usedTags = 0; AssemblyItems m_items; - std::map m_data; + mutable std::map m_data; + std::map m_subs; std::map m_strings; int m_deposit = 0; diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index d19d75090..bc7fa6153 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -44,12 +44,6 @@ void CodeFragment::finalise(CompilerState const& _cs) } } -bytes CodeFragment::code(CompilerState const& _cs) -{ - finalise(_cs); - return m_asm.assemble(); -} - CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) { /* cdebug << "CodeFragment. Locals:"; @@ -499,10 +493,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireMaxSize(3); requireDeposit(1, 1); - code[0].optimise(); - bytes subcode = code[0].code(ns); - - m_asm.append((u256)subcode.size()); + auto subPush = m_asm.appendSubSize(code[0].assembly(ns)); m_asm.append(Instruction::DUP); if (code.size() == 3) { @@ -513,7 +504,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.append(Instruction::MUL); m_asm.append(Instruction::DUP); } - m_asm.append(subcode); + m_asm.append(subPush); m_asm.append(code[1].m_asm, 1); m_asm.append(Instruction::CODECOPY); } diff --git a/liblll/CodeFragment.h b/liblll/CodeFragment.h index 58e409125..98a6f15c7 100644 --- a/liblll/CodeFragment.h +++ b/liblll/CodeFragment.h @@ -43,13 +43,7 @@ public: static CodeFragment compile(std::string const& _src, CompilerState& _s); /// Consolidates data and compiles code. - bytes code(CompilerState const& _cs); - - /// Consolidates data and compiles code. - std::string assembly(CompilerState const& _cs) { finalise(_cs); return m_asm.out(); } - - /// Optimise the code. Best do this just before calling code() or assembly(). - void optimise() { m_asm.optimise(); } + Assembly& assembly(CompilerState const& _cs) { finalise(_cs); return m_asm; } private: void finalise(CompilerState const& _cs); diff --git a/liblll/Compiler.cpp b/liblll/Compiler.cpp index 1621acf90..ebe2638be 100644 --- a/liblll/Compiler.cpp +++ b/liblll/Compiler.cpp @@ -34,9 +34,7 @@ bytes eth::compileLLL(string const& _src, bool _opt, vector* _errors) CompilerState cs; cs.populateStandard(); auto f = CodeFragment::compile(_src, cs); - if (_opt) - f.optimise(); - bytes ret = f.code(cs); + bytes ret = f.assembly(cs).optimise(_opt).assemble(); for (auto i: cs.treesToKill) killBigints(i); return ret; @@ -60,10 +58,7 @@ std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector { CompilerState cs; cs.populateStandard(); - auto f = CodeFragment::compile(_src, cs); - if (_opt) - f.optimise(); - string ret = f.assembly(cs); + string ret = CodeFragment::compile(_src, cs).assembly(cs).optimise(_opt).out(); for (auto i: cs.treesToKill) killBigints(i); return ret; diff --git a/neth/main.cpp b/neth/main.cpp index 50c35b877..c085736b2 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -298,7 +298,7 @@ int nc_window_streambuf::sync() } vector form_dialog(vector _sfields, vector _lfields, vector _bfields, int _cols, int _rows, string _post_form); -bytes parse_data(string _args); +bytes parseData(string _args); int main(int argc, char** argv) @@ -655,7 +655,7 @@ int main(int argc, char** argv) string sdata = fields[5]; cnote << "Data:"; cnote << sdata; - bytes data = parse_data(sdata); + bytes data = parseData(sdata); cnote << "Bytes:"; string sbd = asString(data); bytes bbd = asBytes(sbd); @@ -1223,7 +1223,7 @@ vector form_dialog(vector _sv, vector _lv, vector= (rateof @item) @irate)) {} { + (set 'offerA (min @xoffer (wantof @item))) + (set 'wantA (/ (* @offerA (rateof @item)) (exp 2 128))) ; CHECK! + + (set 'xoffer (- @xoffer @offerA)) + (set 'xwant (- @xwant @wantA)) + + (deductwant @item @offerA) + + (xfer @offer (idof @item) @offerA) + (xfer @want (caller) @wantA) + + (unless @xoffer (stop)) + + (set 'item @@ @item) + [[ @last ]] @item + }) + + (set 'last @list) + (set 'item @@ @last) + + (set 'newpos (newitem @rate (caller) @xwant)) + + (for {} (&& @item (!= @item @newpos) (>= (rateof @item) @rate)) { (set 'last @item) (inc item) } {}) + (if (= @item @newpos) + (addwant @item @wantx) + (stitchitem @last @newpos) + ) + (stop) + }) + (when (= $0 'delete) { + (set 'offer $32) + (set 'want $64) + (set 'list (sha3pair @offer @want)) + (set 'last @list) + (set 'item @@ @last) + (for {} (&& @item (!= (idof @item) (caller))) { (set 'last @item) (inc item) } {}) + (when @item { + (set 'xoffer (/ (* (wantof @item) (rateof @item)) (exp 2 128))) + [[ @last ]] @@ @item + (xfer @offer (caller) @xoffer) + }) + (stop) + }) + (when (= $0 'price) { + (set 'offer $32) + (set 'want $96) + (set 'item (head (sha3pair @offer @want))) + (return (if @item (rateof @list) 0)) + }) +}) +} +"); + +var exchange; +env.note('Create Exchange...') +eth.create(eth.key, '0', exchangeCode, 10000, eth.gasPrice, function(a) { exchange = a; }); + +env.note('Register Exchange...') +eth.transact(eth.key, '0', config, "2".pad(32) + exchange.pad(32), 10000, eth.gasPrice); + + + + env.note('Register my name...') eth.transact(eth.key, '0', nameReg, "register".pad(32) + "Gav".pad(32), 10000, eth.gasPrice);