From 231dc01bc045ea51fd302f119764150973d66d2e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 24 Apr 2015 18:33:37 +0200 Subject: [PATCH] ICAP class for everything ICAP. --- alethzero/MainWin.cpp | 76 +------------------- libdevcore/Base64.h | 21 +++++- libethcore/Common.cpp | 5 +- libethcore/Common.h | 2 + libethcore/ICAP.cpp | 159 ++++++++++++++++++++++++++++++++++++++++++ libethcore/ICAP.h | 77 ++++++++++++++++++++ 6 files changed, 265 insertions(+), 75 deletions(-) create mode 100644 libethcore/ICAP.cpp create mode 100644 libethcore/ICAP.h diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index eb2431f10..792ee6242 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -520,82 +521,11 @@ QString Main::pretty(dev::Address _a) const return fromRaw(n); } -template inline string toBase36(FixedHash const& _h) -{ - static char const* c_alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - typename FixedHash::Arith a = _h; - std::string ret; - for (; a > 0; a /= 36) - ret = c_alphabet[(unsigned)a % 36] + ret; - return ret; -} - -template inline FixedHash fromBase36(string const& _h) -{ - typename FixedHash::Arith ret = 0; - for (char c: _h) - ret = ret * 36 + (c < 'A' ? c - '0' : (c - 'A' + 10)); - return ret; -} - -static string iban(std::string _c, std::string _d) -{ - boost::to_upper(_c); - boost::to_upper(_d); - auto totStr = _d + _c + "00"; - bigint tot = 0; - for (char x: totStr) - if (x >= 'A') - tot = tot * 100 + x - 'A' + 10; - else - tot = tot * 10 + x - '0'; - unsigned check = (unsigned)(u256)(98 - tot % 97); - ostringstream out; - out << _c << setfill('0') << setw(2) << check << _d; - return out.str(); -} - -static std::pair fromIban(std::string _iban) -{ - if (_iban.size() < 4) - return std::make_pair(string(), string()); - boost::to_upper(_iban); - std::string c = _iban.substr(0, 2); - std::string d = _iban.substr(4); - if (iban(c, d) != _iban) - return std::make_pair(string(), string()); - return make_pair(c, d); -} - -static string directICAP(dev::Address _a) -{ - if (!!_a[0]) - return string(); - std::string d = toBase36(_a); - while (d.size() < 30) - d = "0" + d; - return iban("XE", d); -} - -static Address fromICAP(std::string const& _s) -{ - std::string country; - std::string data; - std::tie(country, data) = fromIban(_s); - if (country.empty()) - return Address(); - if (country == "XE" && data.size() == 30) - // Direct ICAP - return fromBase36(data); - // TODO: Indirect ICAP - return Address(); -} - QString Main::render(dev::Address _a) const { QString p = pretty(_a); if (!_a[0]) - p += QString(p.isEmpty() ? "" : " ") + QString::fromStdString(directICAP(_a)); + p += QString(p.isEmpty() ? "" : " ") + QString::fromStdString(ICAP(_a).encoded()); if (!p.isEmpty()) return p + " (" + QString::fromStdString(_a.abridged()) + ")"; return QString::fromStdString(_a.abridged()); @@ -639,7 +569,7 @@ Address Main::fromString(QString const& _n) const return Address(); } } - else if (Address a = fromICAP(_n.toStdString())) + else if (Address a = ICAP::decoded(_n.toStdString()).direct()) return a; else return Address(); diff --git a/libdevcore/Base64.h b/libdevcore/Base64.h index 1e9c88429..8ff10cff0 100644 --- a/libdevcore/Base64.h +++ b/libdevcore/Base64.h @@ -30,7 +30,8 @@ #include #include -#include +#include "Common.h" +#include "FixedHash.h" namespace dev { @@ -38,4 +39,22 @@ namespace dev std::string toBase64(bytesConstRef _in); bytes fromBase64(std::string const& _in); +template inline std::string toBase36(FixedHash const& _h) +{ + static char const* c_alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + typename FixedHash::Arith a = _h; + std::string ret; + for (; a > 0; a /= 36) + ret = c_alphabet[(unsigned)a % 36] + ret; + return ret; +} + +template inline FixedHash fromBase36(std::string const& _h) +{ + typename FixedHash::Arith ret = 0; + for (char c: _h) + ret = ret * 36 + (c < 'A' ? c - '0' : (c - 'A' + 10)); + return ret; +} + } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 56120471b..01c8cfa4c 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -21,6 +21,8 @@ #include "Common.h" #include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" @@ -100,4 +102,5 @@ std::string formatBalance(bigint const& _b) return ret.str(); } -}} +} +} diff --git a/libethcore/Common.h b/libethcore/Common.h index 199057f91..84459c6bf 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -23,6 +23,8 @@ #pragma once +#include +#include #include #include #include diff --git a/libethcore/ICAP.cpp b/libethcore/ICAP.cpp new file mode 100644 index 000000000..107d79db1 --- /dev/null +++ b/libethcore/ICAP.cpp @@ -0,0 +1,159 @@ +/* + 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 ICAP.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "ICAP.h" +#include +#include +#include +#include "Exceptions.h" +using namespace std; +using namespace dev; +using namespace dev::eth; + +namespace dev +{ +namespace eth +{ + +string ICAP::iban(std::string _c, std::string _d) +{ + boost::to_upper(_c); + boost::to_upper(_d); + auto totStr = _d + _c + "00"; + bigint tot = 0; + for (char x: totStr) + if (x >= 'A') + tot = tot * 100 + x - 'A' + 10; + else + tot = tot * 10 + x - '0'; + unsigned check = (unsigned)(u256)(98 - tot % 97); + ostringstream out; + out << _c << setfill('0') << setw(2) << check << _d; + return out.str(); +} + +std::pair ICAP::fromIBAN(std::string _iban) +{ + if (_iban.size() < 4) + return std::make_pair(string(), string()); + boost::to_upper(_iban); + std::string c = _iban.substr(0, 2); + std::string d = _iban.substr(4); + if (iban(c, d) != _iban) + return std::make_pair(string(), string()); + return make_pair(c, d); +} + +ICAP ICAP::decoded(std::string const& _encoded) +{ + ICAP ret; + std::string country; + std::string data; + std::tie(country, data) = fromIBAN(_encoded); + if (country != "XE") + throw InvalidICAP(); + if (data.size() == 30) + { + ret.m_type = Direct; + // Direct ICAP + ret.m_direct = fromBase36(data); + } + else if (data.size() == 16) + { + ret.m_type = Indirect; + ret.m_asset = data.substr(0, 3); + if (ret.m_asset == "XET") + { + ret.m_institution = data.substr(3, 4); + ret.m_client = data.substr(7); + } + else if (ret.m_asset == "ETH") + ret.m_client = data.substr(4); + else + throw InvalidICAP(); + } + else + throw InvalidICAP(); + + return ret; +} + +std::string ICAP::encoded() const +{ + if (m_type == Direct) + { + if (!!m_direct[0]) + return string(); + std::string d = toBase36(m_direct); + while (d.size() < 30) + d = "0" + d; + return iban("XE", d); + } + else if (m_type == Indirect) + { + if ( + m_asset.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos || + m_institution.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos || + m_client.find_first_not_of("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != string::npos || + m_asset.size() != 3 + ) + throw InvalidICAP(); + if (boost::to_upper_copy(m_asset) == "XET") + { + if (m_institution.size() != 4 || m_client.size() != 9) + throw InvalidICAP(); + } + else if (boost::to_upper_copy(m_asset) == "ETH") + { + if (m_client.size() != 13) + throw InvalidICAP(); + } + else + throw InvalidICAP(); + return iban("XE", m_asset + m_institution + m_client); + } + else + throw InvalidICAP(); +} + +Address ICAP::lookup(std::function const& _call, Address const& _reg) const +{ + (void)_call; + (void)_reg; + if (m_asset == "XET") + { + // TODO +// _call(_reg, ); + return Address(); + } + else if (m_asset == "ETH") + { + // TODO + +// return resolve(m_institution + "/" + m_client).primary(); + return Address(); + } + else + throw InterfaceNotSupported("ICAP::lookup(), non XET asset"); +} + +} +} diff --git a/libethcore/ICAP.h b/libethcore/ICAP.h new file mode 100644 index 000000000..60003a1f9 --- /dev/null +++ b/libethcore/ICAP.h @@ -0,0 +1,77 @@ +/* + 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 ICAP.h + * @author Gav Wood + * @date 2014 + * + * Ethereum-specific data structures & algorithms. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +struct InvalidICAP: virtual public dev::Exception {}; + +class ICAP +{ +public: + ICAP() = default; + ICAP(Address const& _a): m_direct(_a) {} + ICAP(std::string const& _target): m_client(_target), m_asset("ETH") {} + ICAP(std::string const& _client, std::string const& _inst): m_client(_client), m_institution(_inst), m_asset("XET") {} + ICAP(std::string const& _c, std::string const& _i, std::string const& _a): m_client(_c), m_institution(_i), m_asset(_a) {} + + enum Type + { + Invalid, + Direct, + Indirect + }; + + static std::string iban(std::string _c, std::string _d); + static std::pair fromIBAN(std::string _iban); + + static ICAP decoded(std::string const& _encoded); + std::string encoded() const; + Type type() const { return m_type; } + + Address const& direct() const { return m_direct; } + Address lookup(std::function const& _call, Address const& _reg) const; + Address address(std::function const& _call, Address const& _reg) const { return m_type == Direct ? direct() : lookup(_call, _reg); } + +private: + Type m_type = Invalid; + Address m_direct; + std::string m_client; + std::string m_institution; + std::string m_asset; +}; + + +} +}