From 770d6f9795e576cc39fdc045940ca9e6d8bd7ccf Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 10 Oct 2014 16:42:10 +0200 Subject: [PATCH] jsonrpc refactor in progress --- .gitignore | 3 + eth/eth.js | 47 +++++++++--- libdevcore/CommonJS.cpp | 152 +++++++++++++++++++++++++++++++++++++ libdevcore/CommonJS.h | 103 +++++++++++++++++++++++++ libdevcore/_libdevcore.cpp | 1 + 5 files changed, 296 insertions(+), 10 deletions(-) create mode 100644 libdevcore/CommonJS.cpp create mode 100644 libdevcore/CommonJS.h diff --git a/.gitignore b/.gitignore index c60cf19e1..b38a3f1e3 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,9 @@ ipch *.opensdf *.suo +# VIM stuff +*.swp + #Xcode stuff build_xc diff --git a/eth/eth.js b/eth/eth.js index 791386a0b..33c65eecc 100644 --- a/eth/eth.js +++ b/eth/eth.js @@ -1,3 +1,5 @@ +// https://github.com/ethereum/cpp-ethereum/wiki/PoC-6-JS-API + if (typeof(window.eth) === "undefined") { if (typeof(require) !== "undefined") @@ -15,23 +17,48 @@ else if (typeof(String.prototype.pad) === "undefined") } var spec = [ - { "method": "procedures", "params": null, "order": [], "returns": [] }, + // properties { "method": "coinbase", "params": null, "order": [], "returns" : "" }, { "method": "isListening", "params": null, "order": [], "returns" : false }, + { "method": "setListening", "params": { "l": "" }, "order" : ["l"], "returns" : ""}, { "method": "isMining", "params": null, "order": [], "returns" : false }, + { "method": "setMining", "params": { "l": "" }, "order" : ["l"], "returns" : ""}, { "method": "gasPrice", "params": null, "order": [], "returns" : "" }, { "method": "key", "params": null, "order": [], "returns" : "" }, { "method": "keys", "params": null, "order": [], "returns" : [] }, { "method": "peerCount", "params": null, "order": [], "returns" : 0 }, - { "method": "balanceAt", "params": { "a": "" }, "order": ["a"], "returns" : "" }, - { "method": "storageAt", "params": { "a": "", "x": "" }, "order": ["a", "x"], "returns" : "" }, - { "method": "stateAt", "params": { "a": "", "x": "", "s": "" }, "order": ["a", "x", "s"], "returns" : "" }, - { "method": "txCountAt", "params": { "a": "" },"order": ["a"], "returns" : "" }, - { "method": "isContractAt", "params": { "a": "" }, "order": ["a"], "returns" : false }, - { "method": "create", "params": { "sec": "", "xEndowment": "", "bCode": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xEndowment", "bCode", "xGas", "xGasPrice"] , "returns": "" }, - { "method": "transact", "params": { "sec": "", "xValue": "", "aDest": "", "bData": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xValue", "aDest", "bData", "xGas", "xGasPrice"], "returns": {} }, - { "method": "secretToAddress", "params": { "a": "" }, "order": ["a"], "returns" : "" }, - { "method": "lll", "params": { "s": "" }, "order": ["s"], "returns" : "" } + { "method": "defaultBlock", "params": null, "order": [], "returns" : 0}, + { "method": "number", "params": null, "order": [], "returns" : 0}, + + // synchronous getters + { "method": "balanceAt", "params": { "a": "", "block": ""}, "order": ["a", "block"], "returns" : ""}, + { "method": "stateAt", "params": { "a": "", "p": "", "block": ""}, "order": ["a", "p", "block"], "returns": ""}, + { "method": "countAt", "params": { "a": "", "block": ""}, "order": ["a", "block"], "returns" : 0}, + { "method": "codeAt", "params": { "a": "", "block": ""}, "order": ["a", "block"], "returns": ""}, + + // transactions + { "method": "transact", "params": { "json": ""}, "order": ["json"], "returns": ""}, + { "method": "call", "params": { "json": ""}, "order": ["json"], "returns": ""}, + + // blockchain + { "method": "block", "params": { "numberOrHash": ""}, "order": ["numberOrHash"], "returns": ""}, + { "method": "transaction", "params": { "numberOrHash": "", "i": ""}, "order": ["numberOrHash", "i"], "returns": ""}, + { "method": "uncle", "params": { "numberOrHash": "", "i": ""}, "order": ["numberOrHash", "i"], "returns": ""}, + + // watches and message filtering + { "method": "messages", "params": { "json": ""}, "order": ["json"], "returns": ""}, + { "method": "watch", "params": { "json": ""}, "order": ["json"], "returns": ""}, + + // misc + { "method": "secretToAddress", "params": { "s": ""}, "order": ["s"], "returns": ""}, + { "method": "lll", "params": { "s": ""}, "order": ["s"], "returns": ""}, + { "method": "sha3", "params": { "s": ""}, "order": ["s"], "returns": ""}, // TODO other sha3 + { "method": "toAscii", "params": { "s": ""}, "order": ["s"], "returns": ""}, + { "method": "fromAscii", "params": { "s": ""}, "order": ["s"], "returns": ""}, // TODO padding + { "method": "toDecimal", "params": {"s": ""}, "order": ["s"], "returns" : ""}, + { "method": "toFixed", "params": {"s": ""}, "order": ["s"], "returns" : ""}, + { "method": "fromFixed", "params": {"s": ""}, "order": ["s"], "returns" : ""}, + { "method": "offset", "params": {"s": "", "offset": ""}, "order": ["s", "offset"], "returns" : ""}, ]; window.eth = (function ethScope() { diff --git a/libdevcore/CommonJS.cpp b/libdevcore/CommonJS.cpp new file mode 100644 index 000000000..4c227bcad --- /dev/null +++ b/libdevcore/CommonJS.cpp @@ -0,0 +1,152 @@ +#include "CommonJS.h" + +namespace dev { +namespace eth { + +bytes dev::eth::jsToBytes(std::string const& _s) +{ + if (_s.substr(0, 2) == "0x") + // Hex + return fromHex(_s.substr(2)); + else if (_s.find_first_not_of("0123456789") == std::string::npos) + // Decimal + return toCompactBigEndian(bigint(_s)); + else + // Binary + return asBytes(_s); +} + +std::string dev::eth::jsPadded(std::string const& _s, unsigned _l, unsigned _r) +{ + bytes b = jsToBytes(_s); + while (b.size() < _l) + b.insert(b.begin(), 0); + while (b.size() < _r) + b.push_back(0); + return asString(b).substr(b.size() - std::max(_l, _r)); +} + +std::string dev::eth::jsPadded(std::string const& _s, unsigned _l) +{ + if (_s.substr(0, 2) == "0x" || _s.find_first_not_of("0123456789") == std::string::npos) + // Numeric: pad to right + return jsPadded(_s, _l, _l); + else + // Text: pad to the left + return jsPadded(_s, 0, _l); +} + +std::string dev::eth::jsUnpadded(std::string _s) +{ + auto p = _s.find_last_not_of((char)0); + _s.resize(p == std::string::npos ? 0 : (p + 1)); + return _s; +} + +dev::eth::Interface* CommonJS::client() const +{ + return m_client; +} + +void CommonJS::setAccounts(std::vector _accounts) +{ + m_accounts = _accounts; +} + +std::string CommonJS::coinbase() const +{ + return m_client ? toJS(client()->address()) : ""; +} + +bool CommonJS::isListening() const +{ + return /*m_client ? client()->haveNetwork() :*/ false; +} + +void CommonJS::setListening(bool _l) +{ + if (!m_client) + return; +/* if (_l) + client()->startNetwork(); + else + client()->stopNetwork();*/ +} + +bool CommonJS::isMining() const +{ + return m_client ? client()->isMining() : false; +} + +void CommonJS::setMining(bool _l) +{ + if (m_client) + { + if (_l) + client()->startMining(); + else + client()->stopMining(); + } +} + +std::string CommonJS::gasPrice() const +{ + return toJS(10 * dev::eth::szabo); +} + +std::string CommonJS::key() const +{ + if (m_accounts.empty()) + return toJS(KeyPair().sec()); + return toJS(m_accounts[0].sec()); +} + +std::vector CommonJS::keys() const +{ + std::vector ret; + for (auto i: m_accounts) + ret.push_back(toJS(i.sec())); + return ret; +} + +unsigned CommonJS::peerCount() const +{ + return /*m_client ? (unsigned)client()->peerCount() :*/ 0; +} + +int CommonJS::defaultBlock() const +{ + return m_client ? m_client->getDefault() : 0; +} + +unsigned CommonJS::number() const +{ + return m_client ? client()->number() + 1 : 0; +} + +std::string CommonJS::balanceAt(const std::string &_a, int _block) const +{ + return m_client ? toJS(client()->balanceAt(jsToAddress(_a), _block)) : ""; +} + +std::string CommonJS::stateAt(const std::string &_a, std::string &_p, int _block) const +{ + return m_client ? toJS(client()->stateAt(jsToAddress(_a), jsToU256(_p), _block)) : ""; +} + +double CommonJS::countAt(const std::string &_a, int _block) const +{ + return m_client ? (double)(uint64_t)client()->countAt(jsToAddress(_a), _block) : 0; +} + +std::string CommonJS::codeAt(const std::string &_a, int _block) const +{ + return m_client ? jsFromBinary(client()->codeAt(jsToAddress(_a), _block)) : ""; +} + + + + + +} +} diff --git a/libdevcore/CommonJS.h b/libdevcore/CommonJS.h new file mode 100644 index 000000000..2e4750589 --- /dev/null +++ b/libdevcore/CommonJS.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include +#include +#include "Common.h" +#include "CommonData.h" + +namespace dev { +namespace eth { + +bytes jsToBytes(std::string const& _s); +std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r); +std::string jsPadded(std::string const& _s, unsigned _l); +std::string jsUnpadded(std::string _s); + +template FixedHash jsToFixed(std::string const& _s) +{ + if (_s.substr(0, 2) == "0x") + // Hex + return FixedHash(_s.substr(2)); + else if (_s.find_first_not_of("0123456789") == std::string::npos) + // Decimal + return (typename FixedHash::Arith)(_s); + else + // Binary + return FixedHash(asBytes(jsPadded(_s, N))); +} + +template boost::multiprecision::number> jsToInt(std::string const& _s) +{ + if (_s.substr(0, 2) == "0x") + // Hex + return fromBigEndian>>(fromHex(_s.substr(2))); + else if (_s.find_first_not_of("0123456789") == std::string::npos) + // Decimal + return boost::multiprecision::number>(_s); + else + // Binary + return fromBigEndian>>(asBytes(jsPadded(_s, N))); +} + +inline Address jsToAddress(std::string const& _s) { return jsToFixed<20>(_s); } +inline Secret jsToSecret(std::string const& _s) { return jsToFixed<32>(_s); } +inline u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); } + +inline std::string jsFromBinary(dev::bytes _s, unsigned _padding = 32) +{ + _s.resize(std::max(_s.size(), _padding)); + return "0x" + dev::toHex(_s); +} + +inline std::string jsFromBinary(std::string const& _s, unsigned _padding = 32) +{ + return jsFromBinary(asBytes(_s), _padding); +} + + +template std::string toJS(FixedHash const& _h) { return "0x" + toHex(_h.ref()); } +template std::string toJS(boost::multiprecision::number> const& _n) { return "0x" + toHex(toCompactBigEndian(_n)); } + +class CommonJS +{ +public: + CommonJS(dev::eth::Interface* _c) : m_client(_c) {} + dev::eth::Interface* client() const; + void setAccounts(std::vector _accounts); + + std::string ethTest() const; + + // properties + std::string coinbase() const; + bool isListening() const; + void setListening(bool _l); + bool isMining() const; + void setMining(bool _l); + std::string /*dev::u256*/ gasPrice() const; + std::string /*dev::KeyPair*/ key() const; + std::vector /*list of dev::KeyPair*/ keys() const; + unsigned peerCount() const; + int defaultBlock() const; + unsigned /*dev::u256*/ number() const; + + // synchronous getters + std::string balanceAt(std::string const &_a, int _block) const; + std::string stateAt(std::string const &_a, std::string &_p, int _block) const; + double countAt(std::string const &_a, int _block) const; + std::string codeAt(std::string const &_a, int _block) const; + + // transactions + void transact(std::string const &_json); + void call(std::string const &_json); + + // blockchain + + +private: + dev::eth::Interface* m_client; + std::vector m_accounts; +}; +} +} + diff --git a/libdevcore/_libdevcore.cpp b/libdevcore/_libdevcore.cpp index 1b34a5911..0605791de 100644 --- a/libdevcore/_libdevcore.cpp +++ b/libdevcore/_libdevcore.cpp @@ -3,6 +3,7 @@ #include "Common.cpp" #include "CommonData.cpp" #include "CommonIO.cpp" +#include "CommonJS.h" #include "FixedHash.cpp" #include "Guards.cpp" #include "Log.cpp"