Browse Source

Merge branch 'develop' of https://github.com/ethereum/cpp-ethereum into build_enhancement

Conflicts:
	libdevcrypto/EC.cpp -> accept-incoming
cl-refactor
sveneh 10 years ago
parent
commit
70ea549657
  1. 28
      alethzero/MainWin.cpp
  2. 3
      alethzero/MainWin.h
  3. 2
      libdevcore/Common.cpp
  4. 1
      libdevcore/Common.h
  5. 8
      libdevcore/CommonData.cpp
  6. 2
      libdevcore/CommonIO.cpp
  7. 31
      libdevcore/CommonJS.cpp
  8. 11
      libdevcore/CommonJS.h
  9. 4
      libdevcore/Exceptions.h
  10. 1
      libdevcore/FixedHash.h
  11. 3
      libdevcore/RLP.h
  12. 42
      libdevcrypto/AES.cpp
  13. 89
      libdevcrypto/AES.h
  14. 8
      libdevcrypto/All.h
  15. 111
      libdevcrypto/Common.cpp
  16. 23
      libdevcrypto/Common.h
  17. 195
      libdevcrypto/CryptoPP.cpp
  18. 78
      libdevcrypto/CryptoPP.h
  19. 200
      libdevcrypto/EC.cpp
  20. 62
      libdevcrypto/EC.h
  21. 100
      libdevcrypto/ECDHE.cpp
  22. 109
      libdevcrypto/ECDHE.h
  23. 10
      libdevcrypto/SHA3.cpp
  24. 3
      libdevcrypto/SHA3.h
  25. 38
      libdevcrypto/SHA3MAC.h
  26. 29
      libethcore/CommonEth.cpp
  27. 36
      libethcore/CryptoHeaders.h
  28. 13
      libethereum/Executive.cpp
  29. 23
      libethereum/State.cpp
  30. 2
      libethereum/TransactionReceipt.h
  31. 2
      libevm/ExtVMFace.h
  32. 3
      libevm/FeeStructure.cpp
  33. 3
      libevm/FeeStructure.h
  34. 27
      libevm/VM.h
  35. 10
      libevmcore/Instruction.cpp
  36. 10
      libp2p/Host.cpp
  37. 1
      libqethereum/QEthereum.h
  38. 3
      libserpent/compiler.cpp
  39. 15
      libsolidity/AST.cpp
  40. 2
      libsolidity/AST.h
  41. 8
      libsolidity/ASTPrinter.cpp
  42. 4
      libsolidity/ASTPrinter.h
  43. 40
      libsolidity/Compiler.cpp
  44. 100
      libsolidity/CompilerStack.cpp
  45. 41
      libsolidity/CompilerStack.h
  46. 17
      libweb3jsonrpc/WebThreeStubServer.cpp
  47. 4
      libwhisper/Common.cpp
  48. 19
      libwhisper/Common.h
  49. 2
      libwhisper/Message.h
  50. 39
      solc/main.cpp
  51. 324
      stdserv.js
  52. 11
      test/TestHelper.cpp
  53. 51
      test/TestHelperCrypto.h
  54. 267
      test/crypto.cpp
  55. 14
      test/solidityCompiler.cpp
  56. 169
      test/solidityEndToEndTest.cpp
  57. 214
      test/solidityJSONInterfaceTest.cpp
  58. 38
      test/stPreCompiledContractsFiller.json
  59. 34
      test/state.cpp
  60. 5
      windows/LibEthereum.vcxproj
  61. 15
      windows/LibEthereum.vcxproj.filters

28
alethzero/MainWin.cpp

@ -353,8 +353,16 @@ void Main::on_enableOptimizer_triggered()
on_data_textChanged(); on_data_textChanged();
} }
QString Main::contents(QString _s)
{
return QString::fromStdString(dev::asString(dev::contents(_s.toStdString())));
}
void Main::load(QString _s) void Main::load(QString _s)
{ {
QString contents = QString::fromStdString(dev::asString(dev::contents(_s.toStdString())));
ui->webView->page()->currentFrame()->evaluateJavaScript(contents);
/*
QFile fin(_s); QFile fin(_s);
if (!fin.open(QFile::ReadOnly)) if (!fin.open(QFile::ReadOnly))
return; return;
@ -375,7 +383,7 @@ void Main::load(QString _s)
//eval(line); //eval(line);
line.clear(); line.clear();
} }
} }*/
} }
void Main::on_loadJS_triggered() void Main::on_loadJS_triggered()
@ -679,7 +687,7 @@ void Main::on_importKeyFile_triggered()
try try
{ {
js::mValue val; js::mValue val;
json_spirit::read_string(asString(contents(s.toStdString())), val); json_spirit::read_string(asString(dev::contents(s.toStdString())), val);
auto obj = val.get_obj(); auto obj = val.get_obj();
if (obj["encseed"].type() == js::str_type) if (obj["encseed"].type() == js::str_type)
{ {
@ -948,7 +956,7 @@ void Main::refreshBlockCount()
cwatch << "refreshBlockCount()"; cwatch << "refreshBlockCount()";
auto d = ethereum()->blockChain().details(); auto d = ethereum()->blockChain().details();
auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty; auto diff = BlockInfo(ethereum()->blockChain().block()).difficulty;
ui->blockCount->setText(QString("%6 #%1 @%3 T%2 N%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet")); ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(dev::eth::c_protocolVersion).arg(dev::eth::c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet"));
} }
static bool blockMatch(string const& _f, dev::eth::BlockDetails const& _b, h256 _h, BlockChain const& _bc) static bool blockMatch(string const& _f, dev::eth::BlockDetails const& _b, h256 _h, BlockChain const& _bc)
@ -1258,9 +1266,10 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Coinbase: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << info.coinbaseAddress; s << "<br/>Coinbase: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << info.coinbaseAddress;
s << "<br/>Nonce: <b>" << info.nonce << "</b>"; s << "<br/>Nonce: <b>" << info.nonce << "</b>";
s << "<br/>Parent: <b>" << info.parentHash << "</b>"; s << "<br/>Parent: <b>" << info.parentHash << "</b>";
s << "<br/>Bloom: <b>" << details.bloom << "</b>"; // s << "<br/>Bloom: <b>" << details.bloom << "</b>";
s << "<br/>Log Bloom: <b>" << info.logBloom << "</b>"; s << "<br/>Log Bloom: <b>" << info.logBloom << "</b>";
s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>"; s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>";
s << "<br/>Receipts: @<b>" << info.receiptsRoot << "</b>:";
s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>"; s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>";
for (auto u: block[2]) for (auto u: block[2])
{ {
@ -1283,6 +1292,7 @@ void Main::on_blocks_currentItemChanged()
Transaction tx(block[1][txi].data()); Transaction tx(block[1][txi].data());
auto ss = tx.safeSender(); auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce())); h256 th = sha3(rlpList(ss, tx.nonce()));
auto receipt = ethereum()->blockChain().receipts(h).receipts[txi];
s << "<h3>" << th << "</h3>"; s << "<h3>" << th << "</h3>";
s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>"; s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>";
s << "<br/>From: <b>" << pretty(ss).toHtmlEscaped().toStdString() << "</b> " << ss; s << "<br/>From: <b>" << pretty(ss).toHtmlEscaped().toStdString() << "</b> " << ss;
@ -1298,6 +1308,10 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>R: <b>" << hex << nouppercase << tx.signature().r << "</b>"; s << "<br/>R: <b>" << hex << nouppercase << tx.signature().r << "</b>";
s << "<br/>S: <b>" << hex << nouppercase << tx.signature().s << "</b>"; s << "<br/>S: <b>" << hex << nouppercase << tx.signature().s << "</b>";
s << "<br/>Msg: <b>" << tx.sha3(eth::WithoutSignature) << "</b>"; s << "<br/>Msg: <b>" << tx.sha3(eth::WithoutSignature) << "</b>";
s << "<div>Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(block[1][txi].data()) << "</span></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(receipt.rlp()) << "</span></div>";
if (tx.isCreation()) if (tx.isCreation())
{ {
if (tx.data().size()) if (tx.data().size())
@ -1602,15 +1616,15 @@ void Main::on_data_textChanged()
} }
else if (src.substr(0, 8) == "contract") // improve this heuristic else if (src.substr(0, 8) == "contract") // improve this heuristic
{ {
shared_ptr<solidity::Scanner> scanner = make_shared<solidity::Scanner>(); dev::solidity::CompilerStack compiler;
try try
{ {
m_data = dev::solidity::CompilerStack::compile(src, scanner, m_enableOptimizer); m_data = compiler.compile(src, m_enableOptimizer);
} }
catch (dev::Exception const& exception) catch (dev::Exception const& exception)
{ {
ostringstream error; ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", *scanner); solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner());
solidity = "<h4>Solidity</h4><pre>" + QString::fromStdString(error.str()).toHtmlEscaped() + "</pre>"; solidity = "<h4>Solidity</h4><pre>" + QString::fromStdString(error.str()).toHtmlEscaped() + "</pre>";
} }
catch (...) catch (...)

3
alethzero/MainWin.h

@ -85,6 +85,7 @@ public slots:
void note(QString _entry); void note(QString _entry);
void debug(QString _entry); void debug(QString _entry);
void warn(QString _entry); void warn(QString _entry);
QString contents(QString _file);
void onKeysChanged(); void onKeysChanged();
@ -154,6 +155,7 @@ private slots:
void on_newIdentity_triggered(); void on_newIdentity_triggered();
void refreshWhisper(); void refreshWhisper();
void refreshBlockChain();
void addNewId(QString _ids); void addNewId(QString _ids);
signals: signals:
@ -214,7 +216,6 @@ private:
void refreshPending(); void refreshPending();
void refreshAccounts(); void refreshAccounts();
void refreshDestination(); void refreshDestination();
void refreshBlockChain();
void refreshBlockCount(); void refreshBlockCount();
void refreshBalances(); void refreshBalances();

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.7.9"; char const* Version = "0.7.10";
} }

1
libdevcore/Common.h

@ -59,6 +59,7 @@ using bytesConstRef = vector_ref<byte const>;
// Numeric types. // Numeric types.
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>; using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
using u128 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<128, 128, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>; using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>; using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;

8
libdevcore/CommonData.cpp

@ -29,14 +29,20 @@ using namespace dev;
std::string dev::escaped(std::string const& _s, bool _all) std::string dev::escaped(std::string const& _s, bool _all)
{ {
static const map<char, char> prettyEscapes{{'\r', 'r'}, {'\n', 'n'}, {'\t', 't'}, {'\v', 'v'}};
std::string ret; std::string ret;
ret.reserve(_s.size()); ret.reserve(_s.size() + 2);
ret.push_back('"'); ret.push_back('"');
for (auto i: _s) for (auto i: _s)
if (i == '"' && !_all) if (i == '"' && !_all)
ret += "\\\""; ret += "\\\"";
else if (i == '\\' && !_all) else if (i == '\\' && !_all)
ret += "\\\\"; ret += "\\\\";
else if (prettyEscapes.count(i))
{
ret += '\\';
ret += prettyEscapes.find(i)->second;
}
else if (i < ' ' || _all) else if (i < ' ' || _all)
{ {
ret += "\\x"; ret += "\\x";

2
libdevcore/CommonIO.cpp

@ -30,7 +30,7 @@ string dev::memDump(bytes const& _b, unsigned _w, bool _html)
{ {
stringstream ret; stringstream ret;
if (_html) if (_html)
ret << "<pre style=\"font-family: Monospace, sans-serif; font-size: small\">"; ret << "<pre style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">";
for (unsigned i = 0; i < _b.size(); i += _w) for (unsigned i = 0; i < _b.size(); i += _w)
{ {
ret << hex << setw(4) << setfill('0') << i << " "; ret << hex << setw(4) << setfill('0') << i << " ";

31
libdevcore/CommonJS.cpp

@ -38,31 +38,20 @@ bytes jsToBytes(std::string const& _s)
return bytes(); return bytes();
} }
std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r) bytes padded(bytes _b, unsigned _l)
{ {
bytes b = jsToBytes(_s); while (_b.size() < _l)
while (b.size() < _l) _b.insert(_b.begin(), 0);
b.insert(b.begin(), 0); while (_b.size() < _l)
while (b.size() < _r) _b.push_back(0);
b.push_back(0); return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
return asString(b).substr(b.size() - std::max(_l, _r));
} }
std::string jsPadded(std::string const& _s, unsigned _l) bytes unpadded(bytes _b)
{ {
if (_s.substr(0, 2) == "0x" || _s.find_first_not_of("0123456789") == std::string::npos) auto p = asString(_b).find_last_not_of((char)0);
// Numeric: pad to right _b.resize(p == std::string::npos ? 0 : (p + 1));
return jsPadded(_s, _l, _l); return _b;
else
// Text: pad to the left
return jsPadded(_s, 0, _l);
}
std::string jsUnpadded(std::string _s)
{
auto p = _s.find_last_not_of((char)0);
_s.resize(p == std::string::npos ? 0 : (p + 1));
return _s;
} }
} }

11
libdevcore/CommonJS.h

@ -47,9 +47,8 @@ inline std::string toJS(dev::bytes const& _n)
} }
bytes jsToBytes(std::string const& _s); bytes jsToBytes(std::string const& _s);
std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r); bytes padded(bytes _b, unsigned _l);
std::string jsPadded(std::string const& _s, unsigned _l); bytes unpadded(bytes _s);
std::string jsUnpadded(std::string _s);
template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s) template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
{ {
@ -61,7 +60,7 @@ template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
return (typename FixedHash<N>::Arith)(_s); return (typename FixedHash<N>::Arith)(_s);
else else
// Binary // Binary
return FixedHash<N>(asBytes(jsPadded(_s, N))); return FixedHash<N>(); // FAIL
} }
inline std::string jsToFixed(double _s) inline std::string jsToFixed(double _s)
@ -79,7 +78,7 @@ template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_i
return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s); return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s);
else else
// Binary // Binary
return fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(jsPadded(_s, N))); return 0; // FAIL
} }
inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev::Address)>(_s); } inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev::Address)>(_s); }
@ -89,7 +88,7 @@ inline u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); }
inline std::string jsToBinary(std::string const& _s) inline std::string jsToBinary(std::string const& _s)
{ {
return jsUnpadded(dev::toString(jsToBytes(_s))); return dev::toString(unpadded(jsToBytes(_s)));
} }
inline std::string jsToDecimal(std::string const& _s) inline std::string jsToDecimal(std::string const& _s)

4
libdevcore/Exceptions.h

@ -45,7 +45,7 @@ struct FileError: virtual Exception {};
typedef boost::error_info<struct tag_invalidSymbol, char> errinfo_invalidSymbol; typedef boost::error_info<struct tag_invalidSymbol, char> errinfo_invalidSymbol;
typedef boost::error_info<struct tag_address, std::string> errinfo_wrongAddress; typedef boost::error_info<struct tag_address, std::string> errinfo_wrongAddress;
typedef boost::error_info<struct tag_comment, std::string> errinfo_comment; typedef boost::error_info<struct tag_comment, std::string> errinfo_comment;
typedef boost::error_info<struct tag_required, size_t> errinfo_required; typedef boost::error_info<struct tag_required, bigint> errinfo_required;
typedef boost::error_info<struct tag_got, size_t> errinfo_got; typedef boost::error_info<struct tag_got, bigint> errinfo_got;
typedef boost::tuple<errinfo_required, errinfo_got> RequirementError; typedef boost::tuple<errinfo_required, errinfo_got> RequirementError;
} }

1
libdevcore/FixedHash.h

@ -240,6 +240,7 @@ using h520 = FixedHash<65>;
using h512 = FixedHash<64>; using h512 = FixedHash<64>;
using h256 = FixedHash<32>; using h256 = FixedHash<32>;
using h160 = FixedHash<20>; using h160 = FixedHash<20>;
using h128 = FixedHash<16>;
using h512s = std::vector<h512>; using h512s = std::vector<h512>;
using h256s = std::vector<h256>; using h256s = std::vector<h256>;
using h160s = std::vector<h160>; using h160s = std::vector<h160>;

3
libdevcore/RLP.h

@ -158,6 +158,7 @@ public:
/// Best-effort conversion operators. /// Best-effort conversion operators.
explicit operator std::string() const { return toString(); } explicit operator std::string() const { return toString(); }
explicit operator bytes() const { return toBytes(); }
explicit operator RLPs() const { return toList(); } explicit operator RLPs() const { return toList(); }
explicit operator uint8_t() const { return toInt<uint8_t>(); } explicit operator uint8_t() const { return toInt<uint8_t>(); }
explicit operator uint16_t() const { return toInt<uint16_t>(); } explicit operator uint16_t() const { return toInt<uint16_t>(); }
@ -341,7 +342,7 @@ public:
RLPStream& append(char const* _s) { return append(std::string(_s)); } RLPStream& append(char const* _s) { return append(std::string(_s)); }
template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); } template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); }
/// Appends an arbitrary RLP fragment - this *must* be a single item. /// Appends an arbitrary RLP fragment - this *must* be a single item unless @a _itemCount is given.
RLPStream& append(RLP const& _rlp, unsigned _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } RLPStream& append(RLP const& _rlp, unsigned _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); }
/// Appends a sequence of data to the stream as a list. /// Appends a sequence of data to the stream as a list.

42
libdevcrypto/SHA3MAC.cpp → libdevcrypto/AES.cpp

@ -14,27 +14,47 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file SHA3MAC.cpp /** @file AES.cpp
* @author Alex Leverington <nessence@gmail.com> * @author Alex Leverington <nessence@gmail.com>
* @date 2014 * @date 2014
*
* SHA3 MAC
*/ */
#include "CryptoPP.h" #include "CryptoPP.h"
#include "SHA3MAC.h" #include "AES.h"
using namespace std;
using namespace dev; using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
using namespace dev::crypto::aes;
using namespace CryptoPP; using namespace CryptoPP;
void crypto::sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) struct aes::Aes128Ctr
{ {
CryptoPP::SHA3_256 ctx; Aes128Ctr(h128 _k)
assert(_secret.size() > 0); {
ctx.Update((byte*)_secret.data(), _secret.size()); mode.SetKeyWithIV(_k.data(), sizeof(h128), Nonce::get().data());
ctx.Update((byte*)_plain.data(), _plain.size()); }
assert(_output.size() >= 32); CTR_Mode<AES>::Encryption mode;
ctx.Final(_output.data()); };
Stream::Stream(StreamType, h128 _ckey):
m_cSecret(_ckey)
{
cryptor = new Aes128Ctr(_ckey);
}
Stream::~Stream()
{
delete cryptor;
}
void Stream::update(bytesRef)
{
}
size_t Stream::streamOut(bytes&)
{
return 0;
} }

89
libdevcrypto/AES.h

@ -0,0 +1,89 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file AES.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* AES
* todo: use openssl
*/
#pragma once
#include <atomic>
#include "Common.h"
namespace dev
{
namespace crypto
{
namespace aes
{
struct Aes128Ctr;
enum StreamType { Encrypt, Decrypt };
/**
* @brief Encrypted stream
*/
class Stream
{
public:
// streamtype maybe irrelevant w/ctr
Stream(StreamType _t, h128 _ckey);
~Stream();
virtual void update(bytesRef io_bytes);
/// Move ciphertext to _bytes.
virtual size_t streamOut(bytes& o_bytes);
private:
Stream(Stream const&) = delete;
Stream& operator=(Stream const&) = delete;
h128 m_cSecret;
bytes m_text;
Aes128Ctr* cryptor;
};
/**
* @brief Encrypted stream with inband SHA3 mac at specific interval.
*/
class AuthenticatedStream: public Stream
{
public:
AuthenticatedStream(StreamType _t, h128 _ckey, h128 _mackey, unsigned _interval): Stream(_t, _ckey), m_macSecret(_mackey) { m_macInterval = _interval; }
AuthenticatedStream(StreamType _t, Secret const& _s, unsigned _interval): Stream(_t, h128(_s)), m_macSecret(FixedHash<16>((byte const*)_s.data()+16,h128::ConstructFromPointer)) { m_macInterval = _interval; }
/// Adjust mac interval. Next mac will be xored with value.
void adjustInterval(unsigned _interval) { m_macInterval = _interval; }
private:
AuthenticatedStream(AuthenticatedStream const&) = delete;
AuthenticatedStream& operator=(AuthenticatedStream const&) = delete;
std::atomic<unsigned> m_macInterval;
h128 m_macSecret;
};
}
}
}

8
libdevcrypto/All.h

@ -1,12 +1,8 @@
#pragma once #pragma once
#include "Common.h" #include "Common.h"
#include "CryptoPP.h" #include "AES.h"
#include "EC.h" #include "ECDHE.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "MemoryDB.h"
#include "OverlayDB.h"
#include "SHA3.h" #include "SHA3.h"
#include "SHA3MAC.h"
#include "TrieCommon.h"
#include "TrieDB.h" #include "TrieDB.h"

111
libdevcrypto/Common.cpp

@ -23,89 +23,104 @@
#include <random> #include <random>
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
#include "EC.h"
#include "SHA3.h" #include "SHA3.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "CryptoPP.h"
#include "Common.h" #include "Common.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace crypto; using namespace dev::crypto;
//#define ETH_ADDRESS_DEBUG 1 static Secp256k1 s_secp256k1;
Address dev::toAddress(Secret _secret) Public dev::toPublic(Secret const& _secret)
{ {
return KeyPair(_secret).address(); Public p;
s_secp256k1.toPublic(_secret, p);
return std::move(p);
} }
KeyPair KeyPair::create() Address dev::toAddress(Public const& _public)
{
static mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (unsigned i = 0; i < 32; ++i)
sec[i] = (byte)d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{ {
toPublic(m_secret, m_public); return s_secp256k1.toAddress(_public);
if (verifySecret(m_secret, m_public))
m_address = right160(dev::sha3(m_public.ref()));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
} }
KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password) Address dev::toAddress(Secret const& _secret)
{ {
return KeyPair(sha3(aesDecrypt(_seed, _password))); Public p;
s_secp256k1.toPublic(_secret, p);
return s_secp256k1.toAddress(p);
} }
void dev::encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher) void dev::encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher)
{ {
bytes io = _plain.toBytes(); bytes io = _plain.toBytes();
crypto::encrypt(_k, io); s_secp256k1.encrypt(_k, io);
o_cipher = std::move(io); o_cipher = std::move(io);
} }
bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext) bool dev::decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext)
{ {
bytes io = _cipher.toBytes(); bytes io = _cipher.toBytes();
crypto::decrypt(_k, io); s_secp256k1.decrypt(_k, io);
if (io.empty()) if (io.empty())
return false; return false;
o_plaintext = std::move(io); o_plaintext = std::move(io);
return true; return true;
} }
Public dev::recover(Signature _sig, h256 _message) Public dev::recover(Signature const& _sig, h256 const& _message)
{
return s_secp256k1.recover(_sig, _message.ref());
}
Signature dev::sign(Secret const& _k, h256 const& _hash)
{
return s_secp256k1.sign(_k, _hash);
}
bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
{
return s_secp256k1.verify(_p, _s, _hash.ref(), true);
}
KeyPair KeyPair::create()
{
static mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i)
{
KeyPair ret(FixedHash<32>::random(s_eng));
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{ {
return crypto::recover(_sig, _message.ref()); if (s_secp256k1.verifySecret(m_secret, m_public))
m_address = s_secp256k1.toAddress(m_public);
} }
Signature dev::sign(Secret _k, h256 _hash) KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password)
{ {
return crypto::sign(_k, _hash); return KeyPair(sha3(aesDecrypt(_seed, _password)));
} }
bool dev::verify(Public _p, Signature _s, h256 _hash) h256 crypto::kdf(Secret const& _priv, h256 const& _hash)
{ {
return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); // H(H(r||k)^h)
h256 s;
sha3mac(Nonce::get().ref(), _priv.ref(), s.ref());
s ^= _hash;
sha3(s.ref(), s.ref());
if (!s || !_hash || !_priv)
BOOST_THROW_EXCEPTION(InvalidState());
return std::move(s);
} }
h256 Nonce::get(bool _commit) h256 Nonce::get(bool _commit)
@ -125,7 +140,7 @@ h256 Nonce::get(bool _commit)
else else
{ {
// todo: replace w/entropy from user and system // todo: replace w/entropy from user and system
std::mt19937_64 s_eng(time(0)); std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
std::uniform_int_distribution<uint16_t> d(0, 255); std::uniform_int_distribution<uint16_t> d(0, 255);
for (unsigned i = 0; i < 32; ++i) for (unsigned i = 0; i < 32; ++i)
s_seed[i] = (byte)d(s_eng); s_seed[i] = (byte)d(s_eng);

23
libdevcrypto/Common.h

@ -52,30 +52,36 @@ using Address = h160;
/// A vector of Ethereum addresses. /// A vector of Ethereum addresses.
using Addresses = h160s; using Addresses = h160s;
/// A vector of Ethereum addresses. /// A set of Ethereum addresses.
using AddressSet = std::set<h160>; using AddressSet = std::set<h160>;
/// A vector of secrets. /// A vector of secrets.
using Secrets = h256s; using Secrets = h256s;
/// Convert a secret key into the public key equivalent. /// Convert a secret key into the public key equivalent.
Public toPublic(Secret const& _secret);
/// Convert a public key to address.
Address toAddress(Public const& _public);
/// Convert a secret key into address of public key equivalent.
/// @returns 0 if it's not a valid secret key. /// @returns 0 if it's not a valid secret key.
Address toAddress(Secret _secret); Address toAddress(Secret const& _secret);
/// Encrypts plain text using Public key. /// Encrypts plain text using Public key.
void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); void encrypt(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
/// Decrypts cipher using Secret key. /// Decrypts cipher using Secret key.
bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); bool decrypt(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Recovers Public key from signed message hash. /// Recovers Public key from signed message hash.
Public recover(Signature _sig, h256 _hash); Public recover(Signature const& _sig, h256 const& _hash);
/// Returns siganture of message hash. /// Returns siganture of message hash.
Signature sign(Secret _k, h256 _hash); Signature sign(Secret const& _k, h256 const& _hash);
/// Verify signature. /// Verify signature.
bool verify(Public _k, Signature _s, h256 _hash); bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
/// Simple class that represents a "key pair". /// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone. /// All of the data of the class can be regenerated from the secret key (m_secret) alone.
@ -119,6 +125,9 @@ namespace crypto
{ {
struct InvalidState: public dev::Exception {}; struct InvalidState: public dev::Exception {};
/// Key derivation
h256 kdf(Secret const& _priv, h256 const& _hash);
/** /**
* @brief Generator for nonce material * @brief Generator for nonce material
*/ */

195
libdevcrypto/CryptoPP.cpp

@ -21,25 +21,206 @@
#include "CryptoPP.h" #include "CryptoPP.h"
using namespace std;
using namespace dev; using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
using namespace CryptoPP; using namespace CryptoPP;
static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes.");
static_assert(dev::Public::size == 64, "Public key must be 64 bytes.");
static_assert(dev::Signature::size == 65, "Signature must be 65 bytes.");
/// Integer and Point Conversion: void Secp256k1::encrypt(Public const& _k, bytes& io_cipher)
{
ECIES<ECP>::Encryptor e;
initializeDLScheme(_k, e);
size_t plen = io_cipher.size();
bytes ciphertext;
ciphertext.resize(e.CiphertextLength(plen));
{
lock_guard<mutex> l(x_rng);
e.Encrypt(m_rng, io_cipher.data(), plen, ciphertext.data());
}
memset(io_cipher.data(), 0, io_cipher.size());
io_cipher = std::move(ciphertext);
}
void Secp256k1::decrypt(Secret const& _k, bytes& io_text)
{
CryptoPP::ECIES<CryptoPP::ECP>::Decryptor d;
initializeDLScheme(_k, d);
size_t clen = io_text.size();
bytes plain;
plain.resize(d.MaxPlaintextLength(io_text.size()));
DecodingResult r;
{
lock_guard<mutex> l(x_rng);
r = d.Decrypt(m_rng, io_text.data(), clen, plain.data());
}
if (!r.isValidCoding)
{
io_text.clear();
return;
}
io_text.resize(r.messageLength);
io_text = std::move(plain);
}
Signature Secp256k1::sign(Secret const& _k, bytesConstRef _message)
{
return sign(_k, sha3(_message));
}
Signature Secp256k1::sign(Secret const& _key, h256 const& _hash)
{
// assumption made by signing alogrithm
asserts(m_q == m_qs);
Signature sig;
Integer k(kdf(_key, _hash).data(), 32);
if (k == 0)
BOOST_THROW_EXCEPTION(InvalidState());
k = 1 + (k % (m_qs - 1));
ECP::Point rp;
Integer r;
{
lock_guard<mutex> l(x_params);
rp = m_params.ExponentiateBase(k);
r = m_params.ConvertElementToInteger(rp);
}
sig[64] = 0;
// sig[64] = (r >= m_q) ? 2 : 0;
Integer kInv = k.InverseMod(m_q);
Integer z(_hash.asBytes().data(), 32);
Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + z)) % m_q;
if (r == 0 || s == 0)
BOOST_THROW_EXCEPTION(InvalidState());
// if (s > m_qs)
// {
// s = m_q - s;
// if (sig[64])
// sig[64] ^= 1;
// }
sig[64] |= rp.y.IsOdd() ? 1 : 0;
r.Encode(sig.data(), 32);
s.Encode(sig.data() + 32, 32);
return sig;
}
bool Secp256k1::verify(Signature const& _signature, bytesConstRef _message)
{
return !!recover(_signature, _message);
}
bool Secp256k1::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed)
{
// todo: verify w/o recovery (if faster)
return _p == _hashed ? recover(_sig, _message) : recover(_sig, sha3(_message).ref());
}
Public Secp256k1::recover(Signature _signature, bytesConstRef _message)
{
Public recovered;
Integer r(_signature.data(), 32);
Integer s(_signature.data()+32, 32);
// cryptopp encodes sign of y as 0x02/0x03 instead of 0/1 or 27/28
byte encodedpoint[33];
encodedpoint[0] = _signature[64]|2;
memcpy(&encodedpoint[1], _signature.data(), 32);
ECP::Element x;
{
lock_guard<mutex> l(x_curve);
m_curve.DecodePoint(x, encodedpoint, 33);
if (!m_curve.VerifyPoint(x))
return recovered;
}
// if (_signature[64] & 2)
// {
// r += m_q;
// lock_guard<mutex> l(x_params);
// if (r >= m_params.GetMaxExponent())
// return recovered;
// }
Integer z(_message.data(), 32);
Integer rn = r.InverseMod(m_q);
Integer u1 = m_q - (rn.Times(z)).Modulo(m_q);
Integer u2 = (rn.Times(s)).Modulo(m_q);
ECP::Point p;
byte recoveredbytes[65];
{
lock_guard<mutex> l(x_curve);
// todo: make generator member
p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator());
m_curve.EncodePoint(recoveredbytes, p, false);
}
memcpy(recovered.data(), &recoveredbytes[1], 64);
return recovered;
}
void pp::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& _p) bool Secp256k1::verifySecret(Secret const& _s, Public& _p)
{
DL_PrivateKey_EC<ECP> k;
k.Initialize(m_params, secretToExponent(_s));
if (!k.Validate(m_rng, 3))
return false;
DL_PublicKey_EC<CryptoPP::ECP> pub;
k.MakePublicKey(pub);
if (!k.Validate(m_rng, 3))
return false;
exportPublicKey(pub, _p);
return true;
}
void Secp256k1::agree(Secret const& _s, Public const& _r, h256& o_s)
{
ECDH<ECP>::Domain d(m_oid);
assert(d.AgreedValueLength() == sizeof(o_s));
byte remote[65] = {0x04};
memcpy(&remote[1], _r.data(), 64);
assert(d.Agree(o_s.data(), _s.data(), remote));
}
void Secp256k1::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p)
{ {
bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true));
secp256k1Params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false);
{
lock_guard<mutex> l(x_params);
m_params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false);
assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true));
memcpy(_p.data(), &prefixedKey[1], Public::size);
} }
void pp::exponentToPublic(Integer const& _e, Public& _p) memcpy(o_p.data(), &prefixedKey[1], Public::size);
}
void Secp256k1::exponentToPublic(Integer const& _e, Public& o_p)
{ {
CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> pk; CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> pk;
pk.Initialize(secp256k1Params, secp256k1Params.ExponentiateBase(_e));
pp::exportPublicKey(pk, _p); {
lock_guard<mutex> l(x_params);
pk.Initialize(m_params, m_params.ExponentiateBase(_e));
}
exportPublicKey(pk, o_p);
} }

78
libdevcrypto/CryptoPP.h

@ -23,6 +23,7 @@
#pragma once #pragma once
#include <mutex>
// need to leave this one disabled for link-time. blame cryptopp. // need to leave this one disabled for link-time. blame cryptopp.
#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-function"
#pragma warning(push) #pragma warning(push)
@ -48,42 +49,85 @@
#include <cryptopp/dsa.h> #include <cryptopp/dsa.h>
#pragma warning(pop) #pragma warning(pop)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#include "SHA3.h"
#include "Common.h" #include "Common.h"
namespace dev namespace dev
{ {
namespace crypto namespace crypto
{ {
namespace pp
{
using namespace CryptoPP; using namespace CryptoPP;
/// CryptoPP random number pool inline ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return std::move(ECP::Point(x,y)); }
static CryptoPP::AutoSeededRandomPool PRNG;
/// CryptoPP EC Cruve inline Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); }
static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1();
static const CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> secp256k1Params(secp256k1Curve); /**
* CryptoPP secp256k1 algorithms.
*/
class Secp256k1
{
public:
Secp256k1(): m_oid(ASN1::secp256k1()), m_params(m_oid), m_curve(m_params.GetCurve()), m_q(m_params.GetGroupOrder()), m_qs(m_params.GetSubgroupOrder()) {}
static ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return std::move(ECP::Point(x,y)); } Address toAddress(Public const& _p) { return right160(sha3(_p.ref())); }
static Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); } void toPublic(Secret const& _s, Public& o_public) { exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public); }
void exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& _p); /// Encrypts text (replace input).
void encrypt(Public const& _k, bytes& io_cipher);
static void exportPrivateKey(CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> const& _k, Secret& _s) { _k.GetPrivateExponent().Encode(_s.data(), Secret::size); } /// Decrypts text (replace input).
void decrypt(Secret const& _k, bytes& io_text);
void exponentToPublic(Integer const& _e, Public& _p); /// @returns siganture of message.
Signature sign(Secret const& _k, bytesConstRef _message);
template <class T> /// @returns compact siganture of provided hash.
void initializeDLScheme(Secret const& _s, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, secretToExponent(_s)); } Signature sign(Secret const& _k, h256 const& _hash);
template <class T> /// Verify compact signature (public key is extracted from signature).
void initializeDLScheme(Public const& _p, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, publicToPoint(_p)); } bool verify(Signature const& _signature, bytesConstRef _message);
/// Verify signature.
bool verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed = false);
/// Recovers public key from compact signature. Uses libsecp256k1.
Public recover(Signature _signature, bytesConstRef _message);
/// Verifies _s is a valid secret key and returns corresponding public key in o_p.
bool verifySecret(Secret const& _s, Public& o_p);
void agree(Secret const& _s, Public const& _r, h256& o_s);
protected:
void exportPrivateKey(DL_PrivateKey_EC<ECP> const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.data(), Secret::size); }
void exportPublicKey(DL_PublicKey_EC<ECP> const& _k, Public& o_p);
void exponentToPublic(Integer const& _e, Public& o_p);
template <class T> void initializeDLScheme(Secret const& _s, T& io_operator) { std::lock_guard<std::mutex> l(x_params); io_operator.AccessKey().Initialize(m_params, secretToExponent(_s)); }
template <class T> void initializeDLScheme(Public const& _p, T& io_operator) { std::lock_guard<std::mutex> l(x_params); io_operator.AccessKey().Initialize(m_params, publicToPoint(_p)); }
private:
OID m_oid;
std::mutex x_rng;
AutoSeededRandomPool m_rng;
std::mutex x_params;
DL_GroupParameters_EC<ECP> m_params;
std::mutex x_curve;
DL_GroupParameters_EC<ECP>::EllipticCurve m_curve;
Integer m_q;
Integer m_qs;
};
}
} }
} }

200
libdevcrypto/EC.cpp

@ -1,200 +0,0 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/**
* @file EC.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* ECDSA, ECIES
*/
#include <secp256k1/secp256k1.h>
#include "CryptoPP.h"
#include "SHA3.h"
#include "SHA3MAC.h"
#include "EC.h"
static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes.");
static_assert(dev::Public::size == 64, "Public key must be 64 bytes.");
static_assert(dev::Signature::size == 65, "Signature must be 65 bytes.");
using namespace std;
using namespace dev;
using namespace dev::crypto;
using namespace CryptoPP;
using namespace pp;
void crypto::toPublic(Secret const& _s, Public& o_public)
{
exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public);
}
h256 crypto::kdf(Secret const& _priv, h256 const& _hash)
{
// H(H(r||k)^h)
h256 s;
sha3mac(Nonce::get().ref(), _priv.ref(), s.ref());
s ^= _hash;
sha3(s.ref(), s.ref());
if (!s || !_hash || !_priv)
BOOST_THROW_EXCEPTION(InvalidState());
return std::move(s);
}
void crypto::encrypt(Public const& _k, bytes& io_cipher)
{
ECIES<ECP>::Encryptor e;
initializeDLScheme(_k, e);
size_t plen = io_cipher.size();
bytes c;
c.resize(e.CiphertextLength(plen));
// todo: use StringSource with io_cipher as input and output.
e.Encrypt(PRNG, io_cipher.data(), plen, c.data());
memset(io_cipher.data(), 0, io_cipher.size());
io_cipher = std::move(c);
}
void crypto::decrypt(Secret const& _k, bytes& io_text)
{
CryptoPP::ECIES<CryptoPP::ECP>::Decryptor d;
initializeDLScheme(_k, d);
size_t clen = io_text.size();
bytes p;
p.resize(d.MaxPlaintextLength(io_text.size()));
// todo: use StringSource with io_text as input and output.
DecodingResult r = d.Decrypt(PRNG, io_text.data(), clen, p.data());
if (!r.isValidCoding)
{
io_text.clear();
return;
}
io_text.resize(r.messageLength);
io_text = std::move(p);
}
Signature crypto::sign(Secret const& _k, bytesConstRef _message)
{
return crypto::sign(_k, sha3(_message));
}
Signature crypto::sign(Secret const& _key, h256 const& _hash)
{
ECDSA<ECP,SHA3_256>::Signer signer;
initializeDLScheme(_key, signer);
Integer const& q = secp256k1Params.GetGroupOrder();
Integer const& qs = secp256k1Params.GetSubgroupOrder();
Integer e(_hash.asBytes().data(), 32);
Integer k(kdf(_key, _hash).data(), 32);
if (k == 0)
BOOST_THROW_EXCEPTION(InvalidState());
k = 1 + (k % (qs - 1));
ECP::Point rp = secp256k1Params.ExponentiateBase(k);
Integer r = secp256k1Params.ConvertElementToInteger(rp);
int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0);
Integer kInv = k.InverseMod(q);
Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + e)) % q;
assert(!!r && !!s);
if (s > qs)
{
s = q - s;
if (recid)
recid ^= 1;
}
Signature sig;
r.Encode(sig.data(), 32);
s.Encode(sig.data() + 32, 32);
sig[64] = recid;
return sig;
}
bool crypto::verify(Signature const& _signature, bytesConstRef _message)
{
return crypto::verify(crypto::recover(_signature, _message), _signature, _message);
}
bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed)
{
static size_t derMaxEncodingLength = 72;
if (_hashed)
{
assert(_message.size() == 32);
byte encpub[65] = {0x04};
memcpy(&encpub[1], _p.data(), 64);
byte dersig[derMaxEncodingLength];
size_t cssz = DSAConvertSignatureFormat(dersig, derMaxEncodingLength, DSA_DER, _sig.data(), 64, DSA_P1363);
assert(cssz <= derMaxEncodingLength);
return (1 == secp256k1_ecdsa_verify(_message.data(), _message.size(), dersig, cssz, encpub, 65));
}
ECDSA<ECP, SHA3_256>::Verifier verifier;
initializeDLScheme(_p, verifier);
return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1);
}
Public crypto::recover(Signature _signature, bytesConstRef _message)
{
secp256k1_start();
int pubkeylen = 65;
byte pubkey[pubkeylen];
if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &pubkeylen, 0, (int)_signature[64]))
return Public();
#if ETH_CRYPTO_TRACE
h256* sig = (h256 const*)_signature.data();
cout << "---- RECOVER -------------------------------" << endl;
cout << "MSG: " << _message << endl;
cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(_signature[64] - 27) << "+27" << endl;
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
#endif
Public ret;
memcpy(&ret, &(pubkey[1]), sizeof(Public));
return ret;
}
bool crypto::verifySecret(Secret const& _s, Public const& _p)
{
secp256k1_start();
int ok = secp256k1_ecdsa_seckey_verify(_s.data());
if (!ok)
return false;
int pubkeylen = 65;
byte pubkey[pubkeylen];
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _s.data(), 0);
if (!ok || pubkeylen != 65)
return false;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return false;
for (int i = 0; i < 32; i++)
if (pubkey[i+1]!=_p[i])
return false;
return true;
}

62
libdevcrypto/EC.h

@ -1,62 +0,0 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file EC.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* ECDSA, ECIES
*/
#pragma once
#include "Common.h"
namespace dev
{
namespace crypto
{
void toPublic(Secret const& _s, Public& o_public);
h256 kdf(Secret const& _priv, h256 const& _hash);
/// Encrypts text (in place).
void encrypt(Public const& _k, bytes& io_cipher);
/// Decrypts text (in place).
void decrypt(Secret const& _k, bytes& io_text);
/// Returns siganture of message.
Signature sign(Secret const& _k, bytesConstRef _message);
/// Returns compact siganture of message hash.
Signature sign(Secret const& _k, h256 const& _hash);
/// Verify compact signature (public key is extracted from message).
bool verify(Signature const& _signature, bytesConstRef _message);
/// Verify signature.
bool verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed = false);
/// Recovers public key from compact signature. Uses libsecp256k1.
Public recover(Signature _signature, bytesConstRef _message);
bool verifySecret(Secret const& _s, Public const& _p);
}
}

100
libdevcrypto/ECDHE.cpp

@ -0,0 +1,100 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file ECDHE.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#include "SHA3.h"
#include "CryptoPP.h"
#include "ECDHE.h"
using namespace std;
using namespace dev;
using namespace dev::crypto;
static Secp256k1 s_secp256k1;
void ECDHE::agree(Public const& _remote, Secret& o_sharedSecret)
{
if (m_remoteEphemeral)
// agreement can only occur once
BOOST_THROW_EXCEPTION(InvalidState());
m_remoteEphemeral = _remote;
s_secp256k1.agree(m_ephemeral.sec(), m_remoteEphemeral, o_sharedSecret);
}
void ECDHEKeyExchange::agree(Public const& _remoteEphemeral)
{
s_secp256k1.agree(m_ephemeral.sec(), _remoteEphemeral, m_ephemeralSecret);
}
void ECDHEKeyExchange::exchange(bytes& o_exchange)
{
if (!m_ephemeralSecret)
// didn't agree on public remote
BOOST_THROW_EXCEPTION(InvalidState());
// The key exchange payload is in two parts and is encrypted
// using ephemeral keypair.
//
// The first part is the 'prefix' which is a zero-knowledge proof
// allowing the remote to resume or emplace a previous session.
// If a session previously exists:
// prefix is sha3(token) // todo: ephemeral entropy from both sides
// If a session doesn't exist:
// prefix is sha3(m_ephemeralSecret)
//
// The second part is encrypted using the public key which relates to the prefix.
Public encpk = m_known.first ? m_known.first : m_remoteEphemeral;
bytes exchange(encpk.asBytes());
// This is the public key which we would like the remote to use,
// which maybe different than the previously-known public key.
//
// Here we should pick an appropriate alias or generate a new one,
// but for now, we use static alias passed to constructor.
//
Public p = toPublic(m_alias.m_secret);
exchange.resize(exchange.size() + sizeof(p));
memcpy(&exchange[exchange.size() - sizeof(p)], p.data(), sizeof(p));
// protocol parameters; should be fixed size
bytes v({0x80});
exchange.resize(exchange.size() + v.size());
memcpy(&exchange[exchange.size() - v.size()], v.data(), v.size());
h256 auth;
sha3mac(m_alias.m_secret.ref(), m_ephemeralSecret.ref(), auth.ref());
Signature sig = s_secp256k1.sign(m_alias.m_secret, auth);
exchange.resize(exchange.size() + sizeof(sig));
memcpy(&exchange[exchange.size() - sizeof(sig)], sig.data(), sizeof(sig));
aes::AuthenticatedStream aes(aes::Encrypt, m_ephemeralSecret, 0);
h256 prefix(sha3(m_known.second ? m_known.second : (h256)m_remoteEphemeral));
aes.update(prefix.ref());
s_secp256k1.encrypt(encpk, exchange);
aes.update(&exchange);
aes.streamOut(o_exchange);
}

109
libdevcrypto/ECDHE.h

@ -0,0 +1,109 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file ECDHE.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* Elliptic curve Diffie-Hellman ephemeral key exchange
*/
#pragma once
#include "AES.h"
namespace dev
{
namespace crypto
{
/// Public key of remote and corresponding shared secret.
typedef std::pair<Public,h256> AliasSession;
/**
* @brief An addressable EC key pair.
*/
class Alias
{
friend class ECDHEKeyExchange; // todo: remove
public:
Alias(Secret _s): m_secret(_s) {};
AliasSession session(Address _a) { return m_sessions.count(_a) ? m_sessions.find(_a)->second : AliasSession(); }
private:
std::map<Address,AliasSession> m_sessions;
Secret m_secret;
};
/**
* @brief Derive DH shared secret from EC keypairs.
* As ephemeral keys are single-use, agreement is limited to a single occurence.
*/
class ECDHE
{
public:
/// Constructor (pass public key for ingress exchange).
ECDHE(): m_ephemeral(KeyPair::create()) {};
/// Public key sent to remote.
Public pubkey() { return m_ephemeral.pub(); }
/// Input public key for dh agreement, output generated shared secret.
void agree(Public const& _remoteEphemeral, Secret& o_sharedSecret);
protected:
KeyPair m_ephemeral; ///< Ephemeral keypair; generated.
Public m_remoteEphemeral; ///< Public key of remote; parameter.
};
/**
* @brief Secure exchange of static keys.
* Key exchange is encrypted with public key of remote and then encrypted by block cipher. For a blind remote the ecdhe public key is used to encrypt exchange, and for a known remote the known public key is used. The block cipher key is derived from ecdhe shared secret.
*
* Usage: Agree -> Exchange -> Authenticate
*/
class ECDHEKeyExchange: private ECDHE
{
public:
/// Exchange with unknown remote (pass public key for ingress exchange)
ECDHEKeyExchange(Alias& _k): m_alias(_k) {};
/// Exchange with known remote
ECDHEKeyExchange(Alias& _k, AliasSession _known): m_alias(_k), m_known(_known) {};
/// Provide public key for dh agreement to generate shared secret.
void agree(Public const& _remoteEphemeral);
/// @returns encrypted payload of key exchange
void exchange(bytes& o_exchange);
/// Decrypt payload, check mac, check trust, decrypt exchange, authenticate exchange, verify version, verify signature, and if no failure occurs, update or creats trust and derive session-shared-secret.
bool authenticate(bytes _exchangeIn);
private:
Secret m_ephemeralSecret;
Alias m_alias;
AliasSession m_known;
Secret m_sharedAliasSecret;
FixedHash<16> m_sharedC;
FixedHash<16> m_sharedM;
};
}
}

10
libdevcrypto/SHA3.cpp

@ -87,6 +87,16 @@ h256 sha3(bytesConstRef _input)
return ret; return ret;
} }
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output)
{
CryptoPP::SHA3_256 ctx;
assert(_secret.size() > 0);
ctx.Update((byte*)_secret.data(), _secret.size());
ctx.Update((byte*)_plain.data(), _plain.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt) bytes aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt)
{ {
bytes pw = asBytes(_password); bytes pw = asBytes(_password);

3
libdevcrypto/SHA3.h

@ -56,6 +56,9 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. /// 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)); } inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
/// Calculate SHA3-256 MAC
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output);
/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash.
template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); } template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); }

38
libdevcrypto/SHA3MAC.h

@ -1,38 +0,0 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file SHA3MAC.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*
* SHA3 MAC
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
namespace crypto
{
void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output);
}
}

29
libethcore/CommonEth.cpp

@ -28,13 +28,12 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
//#define ETH_ADDRESS_DEBUG 1
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
const unsigned c_protocolVersion = 39; const unsigned c_protocolVersion = 42;
const unsigned c_databaseVersion = 4; const unsigned c_databaseVersion = 4;
static const vector<pair<u256, string>> g_units = static const vector<pair<u256, string>> g_units =
@ -84,30 +83,4 @@ std::string formatBalance(u256 _b)
return ret.str(); return ret.str();
} }
Address toAddress(Secret _private)
{
secp256k1_start();
byte pubkey[65];
int pubkeylen = 65;
int ok = secp256k1_ecdsa_seckey_verify(_private.data());
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0);
assert(pubkeylen == 65);
if (!ok)
return Address();
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return Address();
auto ret = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << _private << endl;
cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl;
cout << "ADR: " << ret << endl;
#endif
return ret;
}
}} }}

36
libethcore/CryptoHeaders.h

@ -1,36 +0,0 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file CryptoHeaders.h
* @author Tim Hughes <tim@twistedfury.com>
* @date 2014
*/
#pragma once
// need to leave this one disabled
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma warning(push)
#pragma warning(disable:4100 4244)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <sha.h>
#include <sha3.h>
#include <ripemd.h>
#include <secp256k1/secp256k1.h>
#pragma warning(pop)
#pragma GCC diagnostic pop

13
libethereum/Executive.cpp

@ -71,7 +71,7 @@ bool Executive::setup(bytesConstRef _rlp)
if (m_t.gas() < gasCost) if (m_t.gas() < gasCost)
{ {
clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas(); clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << gasCost << " Got" << m_t.gas();
BOOST_THROW_EXCEPTION(OutOfGas()); BOOST_THROW_EXCEPTION(OutOfGas() << RequirementError((bigint)gasCost, (bigint)m_t.gas()));
} }
u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice(); u256 cost = m_t.value() + m_t.gas() * m_t.gasPrice();
@ -80,14 +80,14 @@ bool Executive::setup(bytesConstRef _rlp)
if (m_s.balance(m_sender) < cost) if (m_s.balance(m_sender) < cost)
{ {
clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender); clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender);
BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((int)cost, (int)m_s.balance(m_sender))); BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((bigint)cost, (bigint)m_s.balance(m_sender)));
} }
u256 startGasUsed = m_s.gasUsed(); u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit) if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit)
{ {
clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas();
BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((int)(m_s.m_currentBlock.gasLimit - startGasUsed), (int)m_t.gas())); BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas()));
} }
// Increment associated nonce for sender. // Increment associated nonce for sender.
@ -123,11 +123,7 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms); m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms);
} }
else else
{
m_endGas = _gas; m_endGas = _gas;
if (m_ext)
m_ext->sub.logs.push_back(LogEntry(_receiveAddress, {u256((u160)_senderAddress) + 1}, bytes()));
}
return !m_ext; return !m_ext;
} }
@ -177,7 +173,10 @@ bool Executive::go(OnOpFunc const& _onOp)
{ {
m_out = m_vm->go(*m_ext, _onOp); m_out = m_vm->go(*m_ext, _onOp);
if (m_ext) if (m_ext)
{
m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds); m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds);
m_logs = m_ext->sub.logs;
}
m_endGas = m_vm->gas(); m_endGas = m_vm->gas();
} }
catch (StepsDone const&) catch (StepsDone const&)

23
libethereum/State.cpp

@ -21,9 +21,10 @@
#include "State.h" #include "State.h"
#include <boost/filesystem.hpp> #include <ctime>
#include <time.h>
#include <random> #include <random>
#include <boost/filesystem.hpp>
#include <boost/timer.hpp>
#include <secp256k1/secp256k1.h> #include <secp256k1/secp256k1.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libevmcore/Instruction.h> #include <libevmcore/Instruction.h>
@ -113,8 +114,6 @@ State::State(Address _coinbaseAddress, OverlayDB const& _db):
m_ourAddress(_coinbaseAddress), m_ourAddress(_coinbaseAddress),
m_blockReward(c_blockReward) m_blockReward(c_blockReward)
{ {
secp256k1_start();
// Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly. // Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly.
m_state.init(); m_state.init();
@ -138,8 +137,6 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
m_state(&m_db), m_state(&m_db),
m_blockReward(c_blockReward) m_blockReward(c_blockReward)
{ {
secp256k1_start();
// TODO THINK: is this necessary? // TODO THINK: is this necessary?
m_state.init(); m_state.init();
@ -325,8 +322,8 @@ StateDiff State::diff(State const& _c) const
for (auto i: _c.m_cache) for (auto i: _c.m_cache)
ads.insert(i.first); ads.insert(i.first);
cnote << *this; // cnote << *this;
cnote << _c; // cnote << _c;
for (auto i: ads) for (auto i: ads)
{ {
@ -553,10 +550,12 @@ h256s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
try try
{ {
uncommitToMine(); uncommitToMine();
// boost::timer t;
execute(i.second); execute(i.second);
ret.push_back(m_receipts.back().changes().bloom()); ret.push_back(m_receipts.back().changes().bloom());
_tq.noteGood(i); _tq.noteGood(i);
++goodTxs; ++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
} }
catch (InvalidNonce const& in) catch (InvalidNonce const& in)
{ {
@ -792,8 +791,6 @@ h256 State::oldBloom() const
LogBloom State::logBloom() const LogBloom State::logBloom() const
{ {
LogBloom ret; LogBloom ret;
auto sa = sha3(m_currentBlock.coinbaseAddress.ref());
ret.shiftBloom<3>(sa);
for (TransactionReceipt const& i: m_receipts) for (TransactionReceipt const& i: m_receipts)
ret |= i.bloom(); ret |= i.bloom();
return ret; return ret;
@ -1242,12 +1239,6 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
return !revert; return !revert;
} }
else
{
// non-contract call
if (o_sub)
o_sub->logs.push_back(LogEntry(_receiveAddress, {u256((u160)_senderAddress) + 1}, bytes()));
}
return true; return true;
} }

2
libethereum/TransactionReceipt.h

@ -55,6 +55,8 @@ public:
l.streamRLP(_s); l.streamRLP(_s);
} }
bytes rlp() const { RLPStream s; streamRLP(s); return s.out(); }
private: private:
h256 m_stateRoot; h256 m_stateRoot;
u256 m_gasUsed; u256 m_gasUsed;

2
libevm/ExtVMFace.h

@ -49,7 +49,7 @@ using LogBloom = h512;
struct LogEntry struct LogEntry
{ {
LogEntry() {} LogEntry() {}
LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = (bytes)_r[2]; } LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = _r[2].toBytes(); }
LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_ts)), data(std::move(_d)) {} LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_ts)), data(std::move(_d)) {}
void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; } void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; }

3
libevm/FeeStructure.cpp

@ -37,3 +37,6 @@ u256 const dev::eth::c_callGas = 20;
u256 const dev::eth::c_memoryGas = 1; u256 const dev::eth::c_memoryGas = 1;
u256 const dev::eth::c_txDataGas = 5; u256 const dev::eth::c_txDataGas = 5;
u256 const dev::eth::c_txGas = 500; u256 const dev::eth::c_txGas = 500;
u256 const dev::eth::c_logGas = 32;
u256 const dev::eth::c_logDataGas = 1;
u256 const dev::eth::c_logTopicGas = 32;

3
libevm/FeeStructure.h

@ -40,6 +40,9 @@ extern u256 const c_callGas; ///< Once per CALL operation & message call trans
extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions. extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions.
extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions. extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions.
extern u256 const c_logGas; ///< Per LOG* operation.
extern u256 const c_logDataGas; ///< Per byte in a LOG* operation's data.
extern u256 const c_logTopicGas; ///< Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
} }
} }

27
libevm/VM.h

@ -71,7 +71,7 @@ public:
template <class Ext> template <class Ext>
bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1); bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1);
void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError(int(_n), m_stack.size())); } void require(u256 _n) { if (m_stack.size() < _n) BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); }
void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
u256 gas() const { return m_gas; } u256 gas() const { return m_gas; }
u256 curPC() const { return m_curPC; } u256 curPC() const { return m_curPC; }
@ -206,14 +206,15 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
{ {
unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0; unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0;
require(n + 2); require(n + 2);
newTempSize = memNeed(m_stack[m_stack.size() - 1 - n], m_stack[m_stack.size() - 2 - n]); runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2];
newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]);
break; break;
} }
case Instruction::CALL: case Instruction::CALL:
case Instruction::CALLCODE: case Instruction::CALLCODE:
require(7); require(7);
runGas = c_callGas + m_stack[m_stack.size() - 1]; runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1];
newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5])); newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]));
break; break;
@ -743,18 +744,38 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;*/ break;*/
case Instruction::LOG0: case Instruction::LOG0:
_ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::LOG1: case Instruction::LOG1:
_ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::LOG2: case Instruction::LOG2:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::LOG3: case Instruction::LOG3:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::LOG4: case Instruction::LOG4:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::CREATE: case Instruction::CREATE:
{ {

10
libevmcore/Instruction.cpp

@ -282,11 +282,11 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::SWAP14, { "SWAP14", 0, 15, 15, false } }, { Instruction::SWAP14, { "SWAP14", 0, 15, 15, false } },
{ Instruction::SWAP15, { "SWAP15", 0, 16, 16, false } }, { Instruction::SWAP15, { "SWAP15", 0, 16, 16, false } },
{ Instruction::SWAP16, { "SWAP16", 0, 17, 17, false } }, { Instruction::SWAP16, { "SWAP16", 0, 17, 17, false } },
{ Instruction::LOG0, { "LOG0", 0, 1, 0, true } }, { Instruction::LOG0, { "LOG0", 0, 2, 0, true } },
{ Instruction::LOG1, { "LOG1", 0, 2, 0, true } }, { Instruction::LOG1, { "LOG1", 0, 3, 0, true } },
{ Instruction::LOG2, { "LOG2", 0, 3, 0, true } }, { Instruction::LOG2, { "LOG2", 0, 4, 0, true } },
{ Instruction::LOG3, { "LOG3", 0, 4, 0, true } }, { Instruction::LOG3, { "LOG3", 0, 5, 0, true } },
{ Instruction::LOG4, { "LOG4", 0, 5, 0, true } }, { Instruction::LOG4, { "LOG4", 0, 6, 0, true } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1, true } }, { Instruction::CREATE, { "CREATE", 0, 3, 1, true } },
{ Instruction::CALL, { "CALL", 0, 7, 1, true } }, { Instruction::CALL, { "CALL", 0, 7, 1, true } },
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1, true } }, { Instruction::CALLCODE, { "CALLCODE", 0, 7, 1, true } },

10
libp2p/Host.cpp

@ -385,8 +385,8 @@ void Host::populateAddresses()
shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId)
{ {
RecursiveGuard l(x_peers); RecursiveGuard l(x_peers);
if (_a.port() < 30300 || _a.port() > 30303) if (_a.port() < 30300 || _a.port() > 30305)
cwarn << "Wierd port being recorded!"; cwarn << "Weird port being recorded: " << _a.port();
if (_a.port() >= /*49152*/32768) if (_a.port() >= /*49152*/32768)
{ {
@ -778,7 +778,7 @@ bytes Host::saveNodes() const
{ {
Node const& n = *(i.second); Node const& n = *(i.second);
// TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 && // TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 &&
if (!n.dead && n.address.port() > 0 && n.address.port() < /*49152*/32768 && n.id != id() && !isPrivateAddress(n.address.address())) if (!n.dead && chrono::system_clock::now() - n.lastConnected < chrono::seconds(3600 * 48) && n.address.port() > 0 && n.address.port() < /*49152*/32768 && n.id != id() && !isPrivateAddress(n.address.address()))
{ {
nodes.appendList(10); nodes.appendList(10);
if (n.address.address().is_v4()) if (n.address.address().is_v4())
@ -786,8 +786,8 @@ bytes Host::saveNodes() const
else else
nodes << n.address.address().to_v6().to_bytes(); nodes << n.address.address().to_v6().to_bytes();
nodes << n.address.port() << n.id << (int)n.idOrigin nodes << n.address.port() << n.id << (int)n.idOrigin
<< std::chrono::duration_cast<std::chrono::seconds>(n.lastConnected.time_since_epoch()).count() << chrono::duration_cast<chrono::seconds>(n.lastConnected.time_since_epoch()).count()
<< std::chrono::duration_cast<std::chrono::seconds>(n.lastAttempted.time_since_epoch()).count() << chrono::duration_cast<chrono::seconds>(n.lastAttempted.time_since_epoch()).count()
<< n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating; << n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating;
count++; count++;
} }

1
libqethereum/QEthereum.h

@ -83,6 +83,7 @@ private:
{ \ { \
_frame->disconnect(); \ _frame->disconnect(); \
_frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \ _frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/main.js")); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/main.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/qt.js")); \ _frame->evaluateJavaScript(contentsOfQResource(":/js/qt.js")); \

3
libserpent/compiler.cpp

@ -131,8 +131,7 @@ programData opcodeify(Node node,
} }
// Declare variable // Declare variable
else { else {
Node nodelist[] = { }; return pd(aux, multiToken(nullptr, 0, m), 0);
return pd(aux, multiToken(nodelist, 0, m), 0);
} }
} }
// Define functions (TODO: eventually move to rewriter.cpp, keep // Define functions (TODO: eventually move to rewriter.cpp, keep

15
libsolidity/AST.cpp

@ -263,6 +263,21 @@ TypeError ASTNode::createTypeError(string const& _description)
return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
} }
vector<FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() const
{
vector<FunctionDefinition const*> exportedFunctions;
for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions)
if (f->isPublic() && f->getName() != getName())
exportedFunctions.push_back(f.get());
auto compareNames = [](FunctionDefinition const* _a, FunctionDefinition const* _b)
{
return _a->getName().compare(_b->getName()) < 0;
};
sort(exportedFunctions.begin(), exportedFunctions.end(), compareNames);
return exportedFunctions;
}
void Block::checkTypeRequirements() void Block::checkTypeRequirements()
{ {
for (shared_ptr<Statement> const& statement: m_statements) for (shared_ptr<Statement> const& statement: m_statements)

2
libsolidity/AST.h

@ -120,6 +120,8 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; } std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; } std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
/// Returns the functions that make up the calling interface in the intended order.
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
private: private:
std::vector<ASTPointer<StructDefinition>> m_definedStructs; std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables; std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;

8
libsolidity/ASTPrinter.cpp

@ -30,8 +30,8 @@ namespace dev
namespace solidity namespace solidity
{ {
ASTPrinter::ASTPrinter(ASTPointer<ASTNode> const& _ast, string const& _source): ASTPrinter::ASTPrinter(ASTNode& _ast, string const& _source):
m_indentation(0), m_source(_source), m_ast(_ast) m_indentation(0), m_source(_source), m_ast(&_ast)
{ {
} }
@ -430,8 +430,8 @@ void ASTPrinter::printSourcePart(ASTNode const& _node)
if (!m_source.empty()) if (!m_source.empty())
{ {
Location const& location(_node.getLocation()); Location const& location(_node.getLocation());
*m_ostream << getIndentation() << " Source: |" *m_ostream << getIndentation() << " Source: "
<< m_source.substr(location.start, location.end - location.start) << "|" << endl; << escaped(m_source.substr(location.start, location.end - location.start), false) << endl;
} }
} }

4
libsolidity/ASTPrinter.h

@ -38,7 +38,7 @@ class ASTPrinter: public ASTVisitor
public: public:
/// Create a printer for the given abstract syntax tree. If the source is specified, /// Create a printer for the given abstract syntax tree. If the source is specified,
/// the corresponding parts of the source are printed with each node. /// the corresponding parts of the source are printed with each node.
ASTPrinter(ASTPointer<ASTNode> const& _ast, std::string const& _source = std::string()); ASTPrinter(ASTNode& _ast, std::string const& _source = std::string());
/// Output the string representation of the AST to _stream. /// Output the string representation of the AST to _stream.
void print(std::ostream& _stream); void print(std::ostream& _stream);
@ -114,7 +114,7 @@ private:
int m_indentation; int m_indentation;
std::string m_source; std::string m_source;
ASTPointer<ASTNode> m_ast; ASTNode* m_ast;
std::ostream* m_ostream; std::ostream* m_ostream;
}; };

40
libsolidity/Compiler.cpp

@ -81,36 +81,34 @@ void Compiler::appendFunctionSelector(vector<ASTPointer<FunctionDefinition>> con
if (publicFunctions.size() > 255) if (publicFunctions.size() > 255)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract.")); BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract."));
//@todo check for calldatasize? // retrieve the first byte of the call data, which determines the called function
// retrieve the first byte of the call data // @todo This code had a jump table in a previous version which was more efficient but also
m_context << u256(0) << eth::Instruction::CALLDATALOAD << u256(0) << eth::Instruction::BYTE; // error prone (due to the optimizer and variable length tag addresses)
// check that it is not too large m_context << u256(1) << u256(0) // some constants
m_context << eth::Instruction::DUP1 << u256(publicFunctions.size() - 1) << eth::Instruction::LT; << eth::dupInstruction(1) << eth::Instruction::CALLDATALOAD
eth::AssemblyItem returnTag = m_context.appendConditionalJump(); << eth::dupInstruction(2) << eth::Instruction::BYTE
<< eth::dupInstruction(2);
// otherwise, jump inside jump table (each entry of the table has size 4)
m_context << u256(4) << eth::Instruction::MUL; // stack here: 1 0 <funid> 0, stack top will be counted up until it matches funid
eth::AssemblyItem jumpTableStart = m_context.pushNewTag();
m_context << eth::Instruction::ADD << eth::Instruction::JUMP;
// jump table, tell the optimizer not to remove the JUMPDESTs
m_context << eth::AssemblyItem(eth::NoOptimizeBegin) << jumpTableStart;
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions) for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
m_context.appendJumpTo(f.second.second) << eth::Instruction::JUMPDEST; {
m_context << eth::AssemblyItem(eth::NoOptimizeEnd); eth::AssemblyItem const& callDataUnpackerEntry = f.second.second;
m_context << eth::dupInstruction(2) << eth::dupInstruction(2) << eth::Instruction::EQ;
m_context << returnTag << eth::Instruction::STOP; m_context.appendConditionalJumpTo(callDataUnpackerEntry);
m_context << eth::dupInstruction(4) << eth::Instruction::ADD;
//@todo avoid the last ADD (or remove it in the optimizer)
}
m_context << eth::Instruction::STOP; // function not found
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions) for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
{ {
FunctionDefinition const& function = *f.second.first; FunctionDefinition const& function = *f.second.first;
m_context << f.second.second; eth::AssemblyItem const& callDataUnpackerEntry = f.second.second;
m_context << callDataUnpackerEntry;
eth::AssemblyItem returnTag = m_context.pushNewTag(); eth::AssemblyItem returnTag = m_context.pushNewTag();
appendCalldataUnpacker(function); appendCalldataUnpacker(function);
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
m_context << returnTag; m_context << returnTag;
appendReturnValuePacker(function); appendReturnValuePacker(function);
} }
} }

100
libsolidity/CompilerStack.cpp

@ -34,17 +34,101 @@ namespace dev
namespace solidity namespace solidity
{ {
bytes CompilerStack::compile(std::string const& _sourceCode, shared_ptr<Scanner> _scanner, void CompilerStack::setSource(string const& _sourceCode)
bool _optimize)
{ {
if (!_scanner) reset();
_scanner = make_shared<Scanner>(); m_scanner = make_shared<Scanner>(CharStream(_sourceCode));
_scanner->reset(CharStream(_sourceCode)); }
void CompilerStack::parse()
{
if (!m_scanner)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source not available."));
m_contractASTNode = Parser().parse(m_scanner);
NameAndTypeResolver().resolveNamesAndTypes(*m_contractASTNode);
m_parseSuccessful = true;
}
void CompilerStack::parse(string const& _sourceCode)
{
setSource(_sourceCode);
parse();
}
bytes const& CompilerStack::compile(bool _optimize)
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
m_bytecode.clear();
m_compiler = make_shared<Compiler>();
m_compiler->compileContract(*m_contractASTNode);
return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
}
bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
{
parse(_sourceCode);
return compile(_optimize);
}
void CompilerStack::streamAssembly(ostream& _outStream)
{
if (!m_compiler || m_bytecode.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
m_compiler->streamAssembly(_outStream);
}
string const& CompilerStack::getInterface()
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
if (m_interface.empty())
{
stringstream interface;
interface << '[';
vector<FunctionDefinition const*> exportedFunctions = m_contractASTNode->getInterfaceFunctions();
unsigned functionsCount = exportedFunctions.size();
for (FunctionDefinition const* f: exportedFunctions)
{
auto streamVariables = [&](vector<ASTPointer<VariableDeclaration>> const& _vars)
{
unsigned varCount = _vars.size();
for (ASTPointer<VariableDeclaration> const& var: _vars)
{
interface << "{"
<< "\"name\":" << escaped(var->getName(), false) << ","
<< "\"type\":" << escaped(var->getType()->toString(), false)
<< "}";
if (--varCount > 0)
interface << ",";
}
};
ASTPointer<ContractDefinition> contract = Parser().parse(_scanner); interface << '{'
NameAndTypeResolver().resolveNamesAndTypes(*contract); << "\"name\":" << escaped(f->getName(), false) << ","
return Compiler::compile(*contract, _optimize); << "\"inputs\":[";
streamVariables(f->getParameters());
interface << "],"
<< "\"outputs\":[";
streamVariables(f->getReturnParameters());
interface << "]"
<< "}";
if (--functionsCount > 0)
interface << ",";
} }
interface << ']';
m_interface = interface.str();
}
return m_interface;
}
bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize)
{
CompilerStack stack;
return stack.compile(_sourceCode, _optimize);
}
} }
} }

41
libsolidity/CompilerStack.h

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <ostream>
#include <string> #include <string>
#include <memory> #include <memory>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
@ -30,13 +31,51 @@ namespace dev {
namespace solidity { namespace solidity {
class Scanner; // forward class Scanner; // forward
class ContractDefinition; // forward
class Compiler; // forward
/**
* Easy to use and self-contained Solidity compiler with as few header dependencies as possible.
* It holds state and can be used to either step through the compilation stages (and abort e.g.
* before compilation to bytecode) or run the whole compilation in one call.
*/
class CompilerStack class CompilerStack
{ {
public: public:
CompilerStack() {}
void reset() { *this = CompilerStack(); }
void setSource(std::string const& _sourceCode);
void parse();
void parse(std::string const& _sourceCode);
/// Compiles the contract that was previously parsed.
bytes const& compile(bool _optimize = false);
/// Parses and compiles the given source code.
bytes const& compile(std::string const& _sourceCode, bool _optimize = false);
bytes const& getBytecode() const { return m_bytecode; }
/// Streams a verbose version of the assembly to @a _outStream.
/// Prerequisite: Successful compilation.
void streamAssembly(std::ostream& _outStream);
/// Returns a string representing the contract interface in JSON.
/// Prerequisite: Successful call to parse or compile.
std::string const& getInterface();
/// Returns the previously used scanner, useful for counting lines during error reporting.
Scanner const& getScanner() const { return *m_scanner; }
ContractDefinition& getAST() const { return *m_contractASTNode; }
/// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for /// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for
/// scanning the source code - this is useful for printing exception information. /// scanning the source code - this is useful for printing exception information.
static bytes compile(std::string const& _sourceCode, std::shared_ptr<Scanner> _scanner = std::shared_ptr<Scanner>(), bool _optimize = false); static bytes staticCompile(std::string const& _sourceCode, bool _optimize = false);
private:
std::shared_ptr<Scanner> m_scanner;
std::shared_ptr<ContractDefinition> m_contractASTNode;
bool m_parseSuccessful;
std::string m_interface;
std::shared_ptr<Compiler> m_compiler;
bytes m_bytecode;
}; };
} }

17
libweb3jsonrpc/WebThreeStubServer.cpp

@ -240,7 +240,7 @@ static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m,
static pair<shh::TopicMask, Public> toWatch(Json::Value const& _json) static pair<shh::TopicMask, Public> toWatch(Json::Value const& _json)
{ {
shh::BuildTopicMask bt(shh::BuildTopicMask::Empty); shh::BuildTopicMask bt;
Public to; Public to;
if (!_json["to"].empty()) if (!_json["to"].empty())
@ -252,12 +252,8 @@ static pair<shh::TopicMask, Public> toWatch(Json::Value const& _json)
bt.shift(jsToBytes(_json["topic"].asString())); bt.shift(jsToBytes(_json["topic"].asString()));
else if (_json["topic"].isArray()) else if (_json["topic"].isArray())
for (auto i: _json["topic"]) for (auto i: _json["topic"])
{
if (i.isString()) if (i.isString())
bt.shift(jsToBytes(i.asString())); bt.shift(jsToBytes(i.asString()));
else
bt.shift();
}
} }
return make_pair(bt.toTopicMask(), to); return make_pair(bt.toTopicMask(), to);
} }
@ -271,14 +267,13 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message
res["ttl"] = (int)_e.ttl(); res["ttl"] = (int)_e.ttl();
res["workProved"] = (int)_e.workProved(); res["workProved"] = (int)_e.workProved();
for (auto const& t: _e.topics()) for (auto const& t: _e.topics())
res["topics"].append(toJS((u256)t)); res["topics"].append(toJS(t));
res["payload"] = toJS(_m.payload()); res["payload"] = toJS(_m.payload());
res["from"] = toJS(_m.from()); res["from"] = toJS(_m.from());
res["to"] = toJS(_m.to()); res["to"] = toJS(_m.to());
return res; return res;
} }
WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts): WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts):
AbstractWebThreeStubServer(_conn), AbstractWebThreeStubServer(_conn),
m_web3(_web3) m_web3(_web3)
@ -375,10 +370,10 @@ static TransactionSkeleton toTransaction(Json::Value const& _json)
ret.data = jsToBytes(_json["code"].asString()); ret.data = jsToBytes(_json["code"].asString());
else if (_json["data"].isArray()) else if (_json["data"].isArray())
for (auto i: _json["data"]) for (auto i: _json["data"])
dev::operator +=(ret.data, jsToBytes(jsPadded(i.asString(), 32))); dev::operator +=(ret.data, padded(jsToBytes(i.asString()), 32));
else if (_json["code"].isArray()) else if (_json["code"].isArray())
for (auto i: _json["code"]) for (auto i: _json["code"])
dev::operator +=(ret.data, jsToBytes(jsPadded(i.asString(), 32))); dev::operator +=(ret.data, padded(jsToBytes(i.asString()), 32));
else if (_json["dataclose"].isArray()) else if (_json["dataclose"].isArray())
for (auto i: _json["dataclose"]) for (auto i: _json["dataclose"])
dev::operator +=(ret.data, jsToBytes(i.asString())); dev::operator +=(ret.data, jsToBytes(i.asString()));
@ -512,7 +507,7 @@ std::string WebThreeStubServer::shh_newGroup(std::string const& _id, std::string
std::string WebThreeStubServer::shh_newIdentity() std::string WebThreeStubServer::shh_newIdentity()
{ {
cnote << this << m_ids; // cnote << this << m_ids;
KeyPair kp = KeyPair::create(); KeyPair kp = KeyPair::create();
m_ids[kp.pub()] = kp.secret(); m_ids[kp.pub()] = kp.secret();
return toJS(kp.pub()); return toJS(kp.pub());
@ -540,7 +535,7 @@ int WebThreeStubServer::eth_peerCount()
bool WebThreeStubServer::shh_post(Json::Value const& _json) bool WebThreeStubServer::shh_post(Json::Value const& _json)
{ {
cnote << this << m_ids; // cnote << this << m_ids;
shh::Message m = toMessage(_json); shh::Message m = toMessage(_json);
Secret from; Secret from;

4
libwhisper/Common.cpp

@ -33,7 +33,7 @@ Topic BuildTopic::toTopic() const
Topic ret; Topic ret;
ret.reserve(m_parts.size()); ret.reserve(m_parts.size());
for (auto const& h: m_parts) for (auto const& h: m_parts)
ret.push_back((TopicPart)u256(h)); ret.push_back(TopicPart(h));
return ret; return ret;
} }
@ -69,7 +69,7 @@ TopicMask BuildTopicMask::toTopicMask() const
TopicMask ret; TopicMask ret;
ret.reserve(m_parts.size()); ret.reserve(m_parts.size());
for (auto const& h: m_parts) for (auto const& h: m_parts)
ret.push_back(make_pair((TopicPart)u256(h), h ? ~(uint32_t)0 : 0)); ret.push_back(make_pair(TopicPart(h), ~TopicPart()));
return ret; return ret;
} }

19
libwhisper/Common.h

@ -59,7 +59,7 @@ enum WhisperPacket
PacketCount PacketCount
}; };
using TopicPart = uint32_t; using TopicPart = FixedHash<4>;
using Topic = std::vector<TopicPart>; using Topic = std::vector<TopicPart>;
@ -92,7 +92,15 @@ public:
TopicFilter() {} TopicFilter() {}
TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {} TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {}
TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {}
TopicFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} TopicFilter(RLP const& _r)//: m_topicMasks(_r.toVector<std::vector<>>())
{
for (RLP i: _r)
{
m_topicMasks.push_back(TopicMask());
for (RLP j: i)
m_topicMasks.back().push_back(j.toPair<FixedHash<4>, FixedHash<4>>());
}
}
void streamRLP(RLPStream& _s) const { _s << m_topicMasks; } void streamRLP(RLPStream& _s) const { _s << m_topicMasks; }
h256 sha3() const; h256 sha3() const;
@ -106,17 +114,12 @@ private:
class BuildTopicMask: BuildTopic class BuildTopicMask: BuildTopic
{ {
public: public:
enum EmptyType { Empty }; BuildTopicMask() {}
BuildTopicMask() { shift(); }
BuildTopicMask(EmptyType) {}
template <class T> BuildTopicMask(T const& _t) { shift(_t); } template <class T> BuildTopicMask(T const& _t) { shift(_t); }
template <class T> BuildTopicMask& shift(T const& _r) { BuildTopic::shift(_r); return *this; } template <class T> BuildTopicMask& shift(T const& _r) { BuildTopic::shift(_r); return *this; }
BuildTopicMask& shiftRaw(h256 const& _h) { BuildTopic::shiftRaw(_h); return *this; } BuildTopicMask& shiftRaw(h256 const& _h) { BuildTopic::shiftRaw(_h); return *this; }
BuildTopic& shift() { m_parts.push_back(h256()); return *this; }
BuildTopicMask& operator()() { shift(); return *this; }
template <class T> BuildTopicMask& operator()(T const& _t) { shift(_t); return *this; } template <class T> BuildTopicMask& operator()(T const& _t) { shift(_t); return *this; }
operator TopicMask() const { return toTopicMask(); } operator TopicMask() const { return toTopicMask(); }

2
libwhisper/Message.h

@ -55,7 +55,7 @@ public:
{ {
m_expiry = _m[0].toInt<unsigned>(); m_expiry = _m[0].toInt<unsigned>();
m_ttl = _m[1].toInt<unsigned>(); m_ttl = _m[1].toInt<unsigned>();
m_topic = (Topic)_m[2]; m_topic = _m[2].toVector<FixedHash<4>>();
m_data = _m[3].toBytes(); m_data = _m[3].toBytes();
m_nonce = _m[4].toInt<u256>(); m_nonce = _m[4].toInt<u256>();
} }

39
solc/main.cpp

@ -26,12 +26,13 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libevmcore/Instruction.h>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h> #include <libsolidity/Parser.h>
#include <libsolidity/ASTPrinter.h> #include <libsolidity/ASTPrinter.h>
#include <libsolidity/NameAndTypeResolver.h> #include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
#include <libsolidity/Compiler.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h> #include <libsolidity/SourceReferenceFormatter.h>
using namespace std; using namespace std;
@ -85,48 +86,34 @@ int main(int argc, char** argv)
else else
sourceCode = asString(dev::contents(infile)); sourceCode = asString(dev::contents(infile));
ASTPointer<ContractDefinition> ast; CompilerStack compiler;
shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(sourceCode));
Parser parser;
bytes instructions;
Compiler compiler;
try try
{ {
ast = parser.parse(scanner); compiler.compile(sourceCode, optimize);
NameAndTypeResolver resolver;
resolver.resolveNamesAndTypes(*ast.get());
cout << "Syntax tree for the contract:" << endl;
dev::solidity::ASTPrinter printer(ast, sourceCode);
printer.print(cout);
compiler.compileContract(*ast);
instructions = compiler.getAssembledBytecode(optimize);
} }
catch (ParserError const& exception) catch (ParserError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", compiler.getScanner());
return -1; return -1;
} }
catch (DeclarationError const& exception) catch (DeclarationError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", compiler.getScanner());
return -1; return -1;
} }
catch (TypeError const& exception) catch (TypeError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", compiler.getScanner());
return -1; return -1;
} }
catch (CompilerError const& exception) catch (CompilerError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", compiler.getScanner());
return -1; return -1;
} }
catch (InternalCompilerError const& exception) catch (InternalCompilerError const& exception)
{ {
cerr << "Internal compiler error: " << boost::diagnostic_information(exception) << endl; SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Internal compiler error", compiler.getScanner());
return -1; return -1;
} }
catch (Exception const& exception) catch (Exception const& exception)
@ -140,11 +127,15 @@ int main(int argc, char** argv)
return -1; return -1;
} }
cout << "Syntax tree for the contract:" << endl;
ASTPrinter printer(compiler.getAST(), sourceCode);
printer.print(cout);
cout << "EVM assembly:" << endl; cout << "EVM assembly:" << endl;
compiler.streamAssembly(cout); compiler.streamAssembly(cout);
cout << "Opcodes:" << endl; cout << "Opcodes:" << endl;
cout << eth::disassemble(instructions) << endl; cout << eth::disassemble(compiler.getBytecode()) << endl;
cout << "Binary: " << toHex(instructions) << endl; cout << "Binary: " << toHex(compiler.getBytecode()) << endl;
cout << "Interface specification: " << compiler.getInterface() << endl;
return 0; return 0;
} }

324
stdserv.js

@ -1,67 +1,41 @@
eth = web3.eth; var compile = function(name) { return web3.eth.lll(env.contents("../../dapp-bin/" + name + "/" + name + ".lll")); };
var create = function(code) { return web3.eth.transact({ 'code': code }); };
env.note('Creating Config...') var send = function(from, val, to) { return web3.eth.transact({ 'from': from, 'value': val, 'to': to }); };
var configCode = eth.lll(" var initService = function(name, index, dep) { return dep.then(function(){ var ret = compile(name).then(create); register(ret, index); return ret; }); };
{
[[69]] (caller) var config = compile("config").then(create);
(returnlll { var register = function(address, index) { return web3.eth.transact({ 'to': config, 'gas': '10000', 'data': [index + '', address] }); };
(when (&& (= (calldatasize) 64) (= (caller) @@69)) var nameReg = initService("namereg", 0, config);
(for {} (< @i (calldatasize)) [i](+ @i 64) var regName = function(account, name) { return web3.eth.transact({ 'from': account, 'to': nameReg, 'gas': '10000', 'data': [ web3.fromAscii('register'), web3.fromAscii(name) ] }); };
[[ (calldataload @i) ]] (calldataload (+ @i 32)) var coins = initService("coins", 1, nameReg);
) var coin = initService("coin", 2, coins);
) var approve = function(account, approvedAddress) { web3.eth.transact({ 'from': account, 'to': coin, 'gas': '10000', 'data': [ web3.fromAscii('approve'), approvedAddress ] }); };
(return @@ $0) var exchange = initService("exchange", 3, coin);
}) var offer = function(account, haveCoin, haveVal, wantCoin, wantVal) { web3.eth.transact({ 'from': account, 'to': exchange, 'gas': '10000', 'data': [web3.fromAscii('new'), haveCoin, haveVal, wantCoin, wantVal] }); };
}
") config.then(function() {
env.note('Config code: ' + configCode) web3.eth.accounts.then(function(accounts)
var config;
eth.transact({ 'code': configCode }, function(a) { config = a; });
env.note('Config at address ' + config)
var nameRegCode = eth.lll("
{ {
[[(address)]] 'NameReg var funded = send(accounts[0], '100000000000000000000', accounts[1]);
[['NameReg]] (address) funded.then(function(){ env.note("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); regName(accounts[1], 'Gav Would'); env.note("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); approve(accounts[1], exchange); });
[[config]] 'Config regName(accounts[0], 'Gav');
[['Config]] config approve(accounts[0], exchange).then(function(){ offer(accounts[0], coin, '5000', '0', '5000000000000000000'); });
[[69]] (caller)
(returnlll { // TODO: once we have a new implementation of DNSReg.
(when (= $0 'register) { // env.note('Register gav.eth...')
(when @@ $32 (stop)) // eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] });
(when @@(caller) [[@@(caller)]] 0) });
[[$32]] (caller) });
[[(caller)]] $32
(stop) // TODO
}) /*
(when (&& (= $0 'unregister) @@(caller)) {
[[@@(caller)]] 0
[[(caller)]] 0
(stop)
})
(when (&& (= $0 'kill) (= (caller) @@69)) (suicide (caller)))
(return @@ $0)
})
}
");
env.note('NameReg code: ' + nameRegCode)
var nameReg;
env.note('Create NameReg...')
eth.transact({ 'code': nameRegCode }, function(a) { nameReg = a; });
env.note('Register NameReg...')
eth.transact({ 'to': config, 'data': ['0', nameReg] });
var nameRegJeff; var nameRegJeff;
env.note('Create NameRegJeff...') env.note('Create NameRegJeff...')
eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; }); eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; });
env.note('Register NameRegJeff...') env.note('Register NameRegJeff...')
eth.transact({ 'to': config, 'data': ['4', nameReg] }); eth.transact({ 'to': config, 'data': ['4', nameRegJeff] });
var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00'; var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00';
@ -73,240 +47,6 @@ env.note('DnsReg at address ' + dnsReg)
env.note('Register DnsReg...') env.note('Register DnsReg...')
eth.transact({ 'to': config, 'data': ['4', dnsReg] }); eth.transact({ 'to': config, 'data': ['4', dnsReg] });
*/
var coinRegCode = eth.lll("
{
(regname 'CoinReg)
(returnlll {
(def 'name $0)
(def 'denom $32)
(def 'address (caller))
(when (|| (& 0xffffffffffffffffffffffffff name) @@name) (stop))
(set 'n (+ @@0 1))
[[0]] @n
[[@n]] name
[[name]] address
[[(sha3 name)]] denom
})
}
");
var coinReg;
env.note('Create CoinReg...')
eth.transact({ 'code': coinRegCode }, function(a) { coinReg = a; });
env.note('Register CoinReg...')
eth.transact({ 'to': config, 'data': ['1', coinReg] });
var gavCoinCode = eth.lll("
{
[[ (caller) ]] 0x1000000
[[ 0x69 ]] (caller)
[[ 0x42 ]] (number)
(regname 'GavCoin)
(regcoin 'GAV 1000)
(returnlll {
(when (&& (= $0 'kill) (= (caller) @@0x69)) (suicide (caller)))
(when (= $0 'balance) (return @@$32))
(when (= $0 'approved) (return @@ (sha3pair (if (= (calldatasize) 64) (caller) $64) $32)) )
(when (= $0 'approve) {
[[(sha3pair (caller) $32)]] $32
(stop)
})
(when (= $0 'send) {
(set 'fromVar (if (= (calldatasize) 96)
(caller)
{
(when (! @@ (sha3pair (origin) (caller))) (return 0))
(origin)
}
))
(def 'to $32)
(def 'value $64)
(def 'from (get 'fromVar))
(set 'fromBal @@from)
(when (< @fromBal value) (return 0))
[[ from ]]: (- @fromBal value)
[[ to ]]: (+ @@to value)
(return 1)
})
(set 'n @@0x42)
(when (&& (|| (= $0 'mine) (! (calldatasize))) (> (number) @n)) {
(set 'b (- (number) @n))
[[(coinbase)]] (+ @@(coinbase) (* 1000 @b))
[[(caller)]] (+ @@(caller) (* 1000 @b))
[[0x42]] (number)
(return @b)
})
(return @@ $0)
})
}
");
var gavCoin;
env.note('Create GavCoin...')
eth.transact({ 'code': gavCoinCode }, function(a) { gavCoin = a; });
env.note('Register GavCoin...')
eth.transact({ 'to': config, 'data': ['2', gavCoin] });
var exchangeCode = eth.lll("
{
(regname 'Exchange)
(def 'min (a b) (if (< a b) a b))
(def 'head (_list) @@ _list)
(def 'next (_item) @@ _item)
(def 'inc (itemref) [itemref]: (next @itemref))
(def 'rateof (_item) @@ (+ _item 1))
(def 'idof (_item) @@ (+ _item 2))
(def 'wantof (_item) @@ (+ _item 3))
(def 'newitem (rate who want list) {
(set 'pos (sha3trip rate who list))
[[ (+ @pos 1) ]] rate
[[ (+ @pos 2) ]] who
[[ (+ @pos 3) ]] want
@pos
})
(def 'stitchitem (parent pos) {
[[ pos ]] @@ parent
[[ parent ]] pos
})
(def 'addwant (_item amount) [[ (+ _item 3) ]] (+ @@ (+ _item 3) amount))
(def 'deductwant (_item amount) [[ (+ _item 3) ]] (- @@ (+ _item 3) amount))
(def 'xfer (contract to amount)
(if contract {
[0] 'send
[32] to
[64] amount
(msg allgas contract 0 0 96)
}
(send to amount)
)
)
(def 'fpdiv (a b) (/ (+ (/ b 2) (* a (exp 2 128))) b))
(def 'fpmul (a b) (/ (* a b) (exp 2 128)) )
(returnlll {
(when (= $0 'new) {
(set 'offer $32)
(set 'xoffer (if @offer $64 (callvalue)))
(set 'want $96)
(set 'xwant $128)
(set 'rate (fpdiv @xoffer @xwant))
(set 'irate (fpdiv @xwant @xoffer))
(unless (&& @rate @irate @xoffer @xwant) (stop))
(when @offer {
(set 'arg1 'send)
(set 'arg2 (address))
(set 'arg3 @xoffer)
(set 'arg4 (caller))
(unless (msg allgas @offer 0 arg1 128) (stop))
})
(set 'list (sha3pair @offer @want))
(set 'ilist (sha3pair @want @offer))
(set 'last @ilist)
(set 'item @@ @last)
(for {} (&& @item (>= (rateof @item) @irate)) {} {
(set 'offerA (min @xoffer (wantof @item)))
(set 'wantA (fpmul @offerA (rateof @item)))
(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 @list))
(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 'rate $96)
(set 'list (sha3pair @offer @want))
(set 'last @list)
(set 'item @@ @last)
(for {} (&& @item (!= (idof @item) (caller)) (!= (rateof @item) @rate)) { (set 'last @item) (inc item) } {})
(when @item {
(set 'xoffer (fpmul (wantof @item) (rateof @item)))
[[ @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.transact({ 'code': exchangeCode }, function(a) { exchange = a; });
env.note('Register Exchange...')
eth.transact({ 'to': config, 'data': ['3', exchange] });
env.note('Register my name...')
eth.transact({ 'to': nameReg, 'data': [ web3.fromAscii('register'), web3.fromAscii('Gav') ] });
env.note('Dole out ETH to other address...')
eth.transact({ 'value': '100000000000000000000', 'to': eth.accounts[1] });
env.note('Register my other name...')
eth.transact({ 'from': eth.keys[1], 'to': nameReg, 'data': [ web3.fromAscii('register'), web3.fromAscii("Gav Would") ] });
env.note('Approve Exchange...')
eth.transact({ 'to': gavCoin, 'data': [ web3.fromAscii('approve'), exchange ] });
env.note('Approve Exchange on other address...')
eth.transact({ 'from': eth.keys[1], 'to': gavCoin, 'data': [ web3.fromAscii('approve'), exchange ] });
env.note('Make offer 5000GAV/5ETH...')
eth.transact({ 'to': exchange, 'data': [web3.fromAscii('new'), gavCoin, '5000', '0', '5000000000000000000'] });
env.note('Register gav.eth...')
eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] });
env.note('All done.')
// env.load('/home/gav/Eth/cpp-ethereum/stdserv.js') // env.load('/home/gav/Eth/cpp-ethereum/stdserv.js')

11
test/TestHelper.cpp

@ -27,8 +27,6 @@
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
//#define FILL_TESTS
using namespace std; using namespace std;
using namespace dev::eth; using namespace dev::eth;
@ -351,7 +349,11 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
string testPath = getTestPath(); string testPath = getTestPath();
testPath += _testPathAppendix; testPath += _testPathAppendix;
#ifdef FILL_TESTS for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--filltests")
{
try try
{ {
cnote << "Populating tests..."; cnote << "Populating tests...";
@ -372,7 +374,8 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
{ {
BOOST_ERROR("Failed test with Exception: " << _e.what()); BOOST_ERROR("Failed test with Exception: " << _e.what());
} }
#endif }
}
try try
{ {

51
test/TestHelperCrypto.h

@ -1,51 +0,0 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file TestHelperCrypto.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#pragma once
#include <libdevcrypto/CryptoPP.h>
using namespace std;
using namespace CryptoPP;
void SavePrivateKey(const PrivateKey& key, const string& file = "ecies.private.key")
{
FileSink sink(file.c_str());
key.Save(sink);
}
void SavePublicKey(const PublicKey& key, const string& file = "ecies.public.key")
{
FileSink sink(file.c_str());
key.Save(sink);
}
void LoadPrivateKey(PrivateKey& key, const string& file = "ecies.private.key")
{
FileSource source(file.c_str(), true);
key.Load(source);
}
void LoadPublicKey(PublicKey& key, const string& file = "ecies.public.key")
{
FileSource source(file.c_str(), true);
key.Load(source);
}

267
test/crypto.cpp

@ -27,9 +27,9 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libethereum/Transaction.h> #include <libethereum/Transaction.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <libdevcrypto/EC.h> #include <libdevcrypto/SHA3.h>
#include <libdevcrypto/SHA3MAC.h> #include <libdevcrypto/ECDHE.h>
#include "TestHelperCrypto.h" #include <libdevcrypto/CryptoPP.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -38,9 +38,24 @@ using namespace CryptoPP;
BOOST_AUTO_TEST_SUITE(devcrypto) BOOST_AUTO_TEST_SUITE(devcrypto)
static Secp256k1 s_secp256k1;
static CryptoPP::AutoSeededRandomPool s_rng;
static CryptoPP::OID s_curveOID(CryptoPP::ASN1::secp256k1());
static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> s_params(s_curveOID);
static CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP>::EllipticCurve s_curve(s_params.GetCurve());
BOOST_AUTO_TEST_CASE(verify_secert)
{
h256 empty;
KeyPair kNot(empty);
BOOST_REQUIRE(!kNot.address());
KeyPair k(sha3(empty));
BOOST_REQUIRE(k.address());
}
BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) BOOST_AUTO_TEST_CASE(common_encrypt_decrypt)
{ {
string message("Now is the time for all good persons to come to the aide of humanity."); string message("Now is the time for all good persons to come to the aid of humanity.");
bytes m = asBytes(message); bytes m = asBytes(message);
bytesConstRef bcr(&m); bytesConstRef bcr(&m);
@ -56,103 +71,50 @@ BOOST_AUTO_TEST_CASE(common_encrypt_decrypt)
BOOST_REQUIRE(plain == asBytes(message)); BOOST_REQUIRE(plain == asBytes(message));
} }
BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1)
{
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::exportPrivateKey(d.GetKey(), s);
Public p;
pp::exportPublicKey(e.GetKey(), p);
BOOST_REQUIRE(dev::toAddress(s) == right160(dev::sha3(p.ref())));
Secret previous = s;
for (auto i = 0; i < 2; i++)
{
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::exportPrivateKey(d.GetKey(), s);
BOOST_REQUIRE(s != previous);
Public p;
pp::exportPublicKey(e.GetKey(), p);
h160 secp256k1Addr = dev::toAddress(s);
h160 cryptoppAddr = right160(dev::sha3(p.ref()));
if (secp256k1Addr != cryptoppAddr)
{
BOOST_REQUIRE(secp256k1Addr == cryptoppAddr);
break;
}
}
}
BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport)
{ {
// cryptopp implementation of secp256k1lib sign_compact w/recid parameter and recovery of public key from signature secp256k1_start();
// base secret // base secret
Secret secret(sha3("privacy")); Secret secret(sha3("privacy"));
// we get ec params from signer // we get ec params from signer
const CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> params = pp::secp256k1Params;
ECDSA<ECP, SHA3_256>::Signer signer; ECDSA<ECP, SHA3_256>::Signer signer;
// e := sha3(msg) // e := sha3(msg)
bytes e(fromHex("0x01")); bytes e(fromHex("0x01"));
e.resize(32); e.resize(32);
int tests = 2; // Oct 29: successful @ 1500 int tests = 2;
while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--)
{ {
KeyPair key(secret); KeyPair key(secret);
Public pkey = key.pub(); Public pkey = key.pub();
pp::initializeDLScheme(secret, signer); signer.AccessKey().Initialize(s_params, secretToExponent(secret));
h256 he(sha3(e)); h256 he(sha3(e));
Integer heInt(he.asBytes().data(), 32); Integer heInt(he.asBytes().data(), 32);
h256 k(crypto::kdf(secret, he)); h256 k(crypto::kdf(secret, he));
Integer kInt(k.asBytes().data(), 32); Integer kInt(k.asBytes().data(), 32);
kInt %= params.GetSubgroupOrder()-1; kInt %= s_params.GetSubgroupOrder()-1;
ECP::Point rp = params.ExponentiateBase(kInt); ECP::Point rp = s_params.ExponentiateBase(kInt);
Integer const& q = params.GetGroupOrder(); Integer const& q = s_params.GetGroupOrder();
Integer r = params.ConvertElementToInteger(rp); Integer r = s_params.ConvertElementToInteger(rp);
int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0);
Integer kInv = kInt.InverseMod(q); Integer kInv = kInt.InverseMod(q);
Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q;
BOOST_REQUIRE(!!r && !!s); BOOST_REQUIRE(!!r && !!s);
/*
// For future reference:
// According to maths, this codepath can't be reached, however, it's in secp256k1.
// Commenting this out diverges from codebase implementation.
// To be removed after upstream PR and proof are evaulated.
if (s > params.GetSubgroupOrder())
{
// note: this rarely happens
s = params.GetGroupOrder() - s;
if (recid)
recid ^= 1;
}
*/
Signature sig; Signature sig;
sig[64] = rp.y.IsOdd() ? 1 : 0;
r.Encode(sig.data(), 32); r.Encode(sig.data(), 32);
s.Encode(sig.data() + 32, 32); s.Encode(sig.data() + 32, 32);
sig[64] = recid;
Public p = dev::recover(sig, he); Public p = dev::recover(sig, he);
BOOST_REQUIRE(p == pkey); BOOST_REQUIRE(p == pkey);
// verify w/cryptopp // verify w/cryptopp
BOOST_REQUIRE(crypto::verify(pkey, sig, bytesConstRef(&e))); BOOST_REQUIRE(s_secp256k1.verify(pkey, sig, bytesConstRef(&e)));
// verify with secp256k1lib // verify with secp256k1lib
byte encpub[65] = {0x04}; byte encpub[65] = {0x04};
@ -166,16 +128,18 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport)
BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1)
{ {
secp256k1_start();
// cryptopp integer encoding // cryptopp integer encoding
Integer nHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); Integer nHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H");
Integer nB(fromHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2").data(), 32); Integer nB(fromHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2").data(), 32);
BOOST_REQUIRE(nHex == nB); BOOST_REQUIRE(nHex == nB);
bytes sbytes(fromHex("0x01")); bytes sbytes(fromHex("0xFFFF"));
Secret secret(sha3(sbytes)); // 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2 Secret secret(sha3(sbytes));
KeyPair key(secret); KeyPair key(secret);
bytes m(fromHex("0x01")); bytes m({0xFF});
int tests = 2; int tests = 2;
while (m[0]++, tests--) while (m[0]++, tests--)
{ {
@ -186,42 +150,42 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1)
// raw sign w/cryptopp (doesn't pass through cryptopp hash filter) // raw sign w/cryptopp (doesn't pass through cryptopp hash filter)
ECDSA<ECP, SHA3_256>::Signer signer; ECDSA<ECP, SHA3_256>::Signer signer;
pp::initializeDLScheme(key.sec(), signer); signer.AccessKey().Initialize(s_params, secretToExponent(key.sec()));
Integer r, s; Integer r, s;
signer.RawSign(kInt, hInt, r, s); signer.RawSign(kInt, hInt, r, s);
// verify cryptopp raw-signature w/cryptopp // verify cryptopp raw-signature w/cryptopp
ECDSA<ECP, SHA3_256>::Verifier verifier; ECDSA<ECP, SHA3_256>::Verifier verifier;
pp::initializeDLScheme(key.pub(), verifier); verifier.AccessKey().Initialize(s_params, publicToPoint(key.pub()));
Signature sigppraw; Signature sigppraw;
r.Encode(sigppraw.data(), 32); r.Encode(sigppraw.data(), 32);
s.Encode(sigppraw.data() + 32, 32); s.Encode(sigppraw.data() + 32, 32);
BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64));
BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m))); // BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m)));
BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm)); BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm));
// sign with cryptopp, verify, recover w/sec256lib // sign with cryptopp, verify, recover w/sec256lib
Signature seclibsig(dev::sign(key.sec(), hm)); Signature seclibsig(dev::sign(key.sec(), hm));
BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64));
BOOST_REQUIRE(crypto::verify(key.pub(), seclibsig, bytesConstRef(&m))); // BOOST_REQUIRE(crypto::verify(key.pub(), seclibsig, bytesConstRef(&m)));
BOOST_REQUIRE(dev::verify(key.pub(), seclibsig, hm)); BOOST_REQUIRE(dev::verify(key.pub(), seclibsig, hm));
BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub()); BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub());
// sign with cryptopp (w/hash filter?), verify with cryptopp // sign with cryptopp (w/hash filter?), verify with cryptopp
bytes sigppb(signer.MaxSignatureLength()); bytes sigppb(signer.MaxSignatureLength());
size_t ssz = signer.SignMessage(pp::PRNG, m.data(), m.size(), sigppb.data()); size_t ssz = signer.SignMessage(s_rng, m.data(), m.size(), sigppb.data());
Signature sigpp; Signature sigpp;
memcpy(sigpp.data(), sigppb.data(), 64); memcpy(sigpp.data(), sigppb.data(), 64);
BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz));
BOOST_REQUIRE(crypto::verify(key.pub(), sigpp, bytesConstRef(&m))); // BOOST_REQUIRE(crypto::verify(key.pub(), sigpp, bytesConstRef(&m)));
BOOST_REQUIRE(dev::verify(key.pub(), sigpp, hm)); BOOST_REQUIRE(dev::verify(key.pub(), sigpp, hm));
// sign with cryptopp and stringsource hash filter // sign with cryptopp and stringsource hash filter
string sigstr; string sigstr;
StringSource ssrc(asString(m), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); StringSource ssrc(asString(m), true, new SignerFilter(s_rng, signer, new StringSink(sigstr)));
FixedHash<sizeof(Signature)> retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); FixedHash<sizeof(Signature)> retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer);
BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64));
BOOST_REQUIRE(crypto::verify(key.pub(), retsig, bytesConstRef(&m))); // BOOST_REQUIRE(crypto::verify(key.pub(), retsig, bytesConstRef(&m)));
BOOST_REQUIRE(dev::verify(key.pub(), retsig, hm)); BOOST_REQUIRE(dev::verify(key.pub(), retsig, hm));
/// verification w/sec256lib /// verification w/sec256lib
@ -247,92 +211,102 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1)
} }
} }
BOOST_AUTO_TEST_CASE(cryptopp_public_export_import)
{
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::Encryptor e(d.GetKey());
Secret s;
pp::exportPrivateKey(d.GetKey(), s);
Public p;
pp::exportPublicKey(e.GetKey(), p);
Address addr = right160(dev::sha3(p.ref()));
BOOST_REQUIRE(toAddress(s) == addr);
KeyPair l(s);
BOOST_REQUIRE(l.address() == addr);
}
BOOST_AUTO_TEST_CASE(ecies_eckeypair) BOOST_AUTO_TEST_CASE(ecies_eckeypair)
{ {
KeyPair k = KeyPair::create(); KeyPair k = KeyPair::create();
string message("Now is the time for all good persons to come to the aide of humanity."); string message("Now is the time for all good persons to come to the aid of humanity.");
string original = message; string original = message;
bytes b = asBytes(message); bytes b = asBytes(message);
encrypt(k.pub(), b); s_secp256k1.encrypt(k.pub(), b);
BOOST_REQUIRE(b != asBytes(original)); BOOST_REQUIRE(b != asBytes(original));
decrypt(k.sec(), b); s_secp256k1.decrypt(k.sec(), b);
BOOST_REQUIRE(b == asBytes(original)); BOOST_REQUIRE(b == asBytes(original));
} }
BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) BOOST_AUTO_TEST_CASE(ecdh)
{ {
// New connections require new ECDH keypairs cnote << "Testing ecdh...";
// Every new connection requires a new EC keypair
// Every new trust requires a new EC keypair
// All connections should share seed for PRF (or PRNG) for nonces
ECDH<ECP>::Domain dhLocal(s_curveOID);
SecByteBlock privLocal(dhLocal.PrivateKeyLength());
SecByteBlock pubLocal(dhLocal.PublicKeyLength());
dhLocal.GenerateKeyPair(s_rng, privLocal, pubLocal);
} ECDH<ECP>::Domain dhRemote(s_curveOID);
SecByteBlock privRemote(dhRemote.PrivateKeyLength());
SecByteBlock pubRemote(dhRemote.PublicKeyLength());
dhRemote.GenerateKeyPair(s_rng, privRemote, pubRemote);
BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength());
{
cnote << "Testing cryptopp_ecies_message..."; // local: send public to remote; remote: send public to local
// Local
SecByteBlock sharedLocal(dhLocal.AgreedValueLength());
assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote));
// Remote
SecByteBlock sharedRemote(dhRemote.AgreedValueLength());
assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal));
// Test
Integer ssLocal, ssRemote;
ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes());
ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes());
assert(ssLocal != 0);
assert(ssLocal == ssRemote);
string const message("Now is the time for all good persons to come to the aide of humanity.");
ECIES<ECP>::Decryptor localDecryptor(pp::PRNG, pp::secp256k1Curve); // Now use our keys
SavePrivateKey(localDecryptor.GetPrivateKey()); KeyPair a = KeyPair::create();
byte puba[65] = {0x04};
memcpy(&puba[1], a.pub().data(), 64);
ECIES<ECP>::Encryptor localEncryptor(localDecryptor); KeyPair b = KeyPair::create();
SavePublicKey(localEncryptor.GetPublicKey()); byte pubb[65] = {0x04};
memcpy(&pubb[1], b.pub().data(), 64);
ECIES<ECP>::Decryptor futureDecryptor; ECDH<ECP>::Domain dhA(s_curveOID);
LoadPrivateKey(futureDecryptor.AccessPrivateKey()); Secret shared;
futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG, 3); BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb));
BOOST_REQUIRE(shared);
}
BOOST_AUTO_TEST_CASE(ecdhe)
{
cnote << "Testing ecdhe...";
ECIES<ECP>::Encryptor futureEncryptor; ECDHE a, b;
LoadPublicKey(futureEncryptor.AccessPublicKey()); BOOST_CHECK_NE(a.pubkey(), b.pubkey());
futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG, 3);
// encrypt/decrypt with local ECDHE local;
string cipherLocal; ECDHE remote;
StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG, localEncryptor, new StringSink(cipherLocal) ) );
string plainLocal;
StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocal) ) );
// encrypt/decrypt with future // local tx pubkey -> remote
string cipherFuture; Secret sremote;
StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG, futureEncryptor, new StringSink(cipherFuture) ) ); remote.agree(local.pubkey(), sremote);
string plainFuture;
StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFuture) ) );
// decrypt local w/future // remote tx pbukey -> local
string plainFutureFromLocal; Secret slocal;
StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); local.agree(remote.pubkey(), slocal);
// decrypt future w/local BOOST_REQUIRE(sremote);
string plainLocalFromFuture; BOOST_REQUIRE(slocal);
StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocalFromFuture) ) ); BOOST_REQUIRE_EQUAL(sremote, slocal);
}
BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac)
{
// New connections require new ECDH keypairs
// Every new connection requires a new EC keypair
// Every new trust requires a new EC keypair
// All connections should share seed for PRF (or PRNG) for nonces
BOOST_REQUIRE(plainLocal == message);
BOOST_REQUIRE(plainFuture == plainLocal);
BOOST_REQUIRE(plainFutureFromLocal == plainLocal);
BOOST_REQUIRE(plainLocalFromFuture == plainLocal);
} }
BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
@ -346,21 +320,28 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
rng.GenerateBlock(key, key.size()); rng.GenerateBlock(key, key.size());
// cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr // cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr
byte ctr[AES::BLOCKSIZE]; FixedHash<AES::BLOCKSIZE> ctr;
rng.GenerateBlock(ctr, sizeof(ctr)); rng.GenerateBlock(ctr.data(), sizeof(ctr));
string text = "Now is the time for all good persons to come to the aide of humanity."; // used for decrypt
// c++11 ftw FixedHash<AES::BLOCKSIZE> ctrcopy(ctr);
string text = "Now is the time for all good persons to come to the aid of humanity.";
unsigned char const* in = (unsigned char*)&text[0]; unsigned char const* in = (unsigned char*)&text[0];
unsigned char* out = (unsigned char*)&text[0]; unsigned char* out = (unsigned char*)&text[0];
string original = text; string original = text;
string doublespeak = text + text;
string cipherCopy; string cipherCopy;
try try
{ {
CTR_Mode<AES>::Encryption e; CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), ctr); e.SetKeyWithIV(key, key.size(), ctr.data());
// 68 % 255 should be difference of counter
e.ProcessData(out, in, text.size()); e.ProcessData(out, in, text.size());
ctr = h128(u128(ctr) + text.size() % 16);
BOOST_REQUIRE(text != original); BOOST_REQUIRE(text != original);
cipherCopy = text; cipherCopy = text;
} }
@ -372,7 +353,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
try try
{ {
CTR_Mode< AES >::Decryption d; CTR_Mode< AES >::Decryption d;
d.SetKeyWithIV(key, key.size(), ctr); d.SetKeyWithIV(key, key.size(), ctrcopy.data());
d.ProcessData(out, in, text.size()); d.ProcessData(out, in, text.size());
BOOST_REQUIRE(text == original); BOOST_REQUIRE(text == original);
} }
@ -390,7 +371,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr)
out = (unsigned char*)&cipherCopy[0]; out = (unsigned char*)&cipherCopy[0];
CTR_Mode<AES>::Encryption e; CTR_Mode<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), ctr); e.SetKeyWithIV(key, key.size(), ctrcopy.data());
e.ProcessData(out, in, text.size()); e.ProcessData(out, in, text.size());
// yep, ctr mode. // yep, ctr mode.

14
test/solidityCompiler.cpp

@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 51; unsigned boilerplateSize = 42;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x0, // initialize local variable x
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
@ -100,8 +100,8 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 75; unsigned shift = 70;
unsigned boilerplateSize = 88; unsigned boilerplateSize = 83;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize return variable d byte(Instruction::PUSH1), 0x0, // initialize return variable d
byte(Instruction::DUP3), byte(Instruction::DUP3),
@ -153,8 +153,8 @@ BOOST_AUTO_TEST_CASE(ifStatement)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 38; unsigned shift = 29;
unsigned boilerplateSize = 51; unsigned boilerplateSize = 42;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), byte(Instruction::DUP1),
@ -195,8 +195,8 @@ BOOST_AUTO_TEST_CASE(loops)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 38; unsigned shift = 29;
unsigned boilerplateSize = 51; unsigned boilerplateSize = 42;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,

169
test/solidityEndToEndTest.cpp

@ -22,6 +22,7 @@
*/ */
#include <string> #include <string>
#include <tuple>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <libethereum/State.h> #include <libethereum/State.h>
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
@ -41,36 +42,72 @@ class ExecutionFramework
public: public:
ExecutionFramework() { g_logVerbosity = 0; } ExecutionFramework() { g_logVerbosity = 0; }
bytes const& compileAndRun(std::string const& _sourceCode) bytes const& compileAndRun(string const& _sourceCode)
{ {
bytes code = dev::solidity::CompilerStack::compile(_sourceCode); bytes code = dev::solidity::CompilerStack::staticCompile(_sourceCode);
sendMessage(code, true); sendMessage(code, true);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
return m_output; return m_output;
} }
bytes const& callFunction(byte _index, bytes const& _data) bytes const& callContractFunction(byte _index, bytes const& _data = bytes())
{ {
sendMessage(bytes(1, _index) + _data, false); sendMessage(bytes(1, _index) + _data, false);
return m_output; return m_output;
} }
bytes const& callFunction(byte _index, u256 const& _argument1) template <class... Args>
bytes const& callContractFunction(byte _index, Args const&... _arguments)
{ {
return callFunction(_index, toBigEndian(_argument1)); return callContractFunction(_index, argsToBigEndian(_arguments...));
} }
bool testSolidityAgainstCpp(byte _index, std::function<u256(u256)> const& _cppfun, u256 const& _argument1) template <class CppFunction, class... Args>
void testSolidityAgainstCpp(byte _index, CppFunction const& _cppFunction, Args const&... _arguments)
{ {
return toBigEndian(_cppfun(_argument1)) == callFunction(_index, toBigEndian(_argument1)); bytes solidityResult = callContractFunction(_index, _arguments...);
bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...);
BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match."
"\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult));
} }
bool testSolidityAgainstCpp(byte _index, std::function<u256()> const& _cppfun) template <class CppFunction, class... Args>
void testSolidityAgainstCppOnRange(byte _index, CppFunction const& _cppFunction,
u256 const& _rangeStart, u256 const& _rangeEnd)
{ {
return toBigEndian(_cppfun()) == callFunction(_index, bytes()); for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument)
{
bytes solidityResult = callContractFunction(_index, argument);
bytes cppResult = callCppAndEncodeResult(_cppFunction, argument);
BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match."
"\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult) +
"\nArgument: " + toHex(toBigEndian(argument)));
}
} }
private: private:
template <class FirstArg, class... Args>
bytes argsToBigEndian(FirstArg const& _firstArg, Args const&... _followingArgs) const
{
return toBigEndian(_firstArg) + argsToBigEndian(_followingArgs...);
}
bytes argsToBigEndian() const { return bytes(); }
template <class CppFunction, class... Args>
auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments)
-> typename enable_if<is_void<decltype(_cppFunction(_arguments...))>::value, bytes>::type
{
_cppFunction(_arguments...);
return bytes();
}
template <class CppFunction, class... Args>
auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments)
-> typename enable_if<!is_void<decltype(_cppFunction(_arguments...))>::value, bytes>::type
{
return toBigEndian(_cppFunction(_arguments...));
}
void sendMessage(bytes const& _data, bool _isCreation) void sendMessage(bytes const& _data, bool _isCreation)
{ {
eth::Executive executive(m_state); eth::Executive executive(m_state);
@ -91,7 +128,10 @@ private:
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
} }
else else
{
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address()));
}
BOOST_REQUIRE(executive.go()); BOOST_REQUIRE(executive.go());
executive.finalize(); executive.finalize();
m_output = executive.out().toVector(); m_output = executive.out().toVector();
@ -112,8 +152,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
" function f(uint a) returns(uint d) { return a * 7; }\n" " function f(uint a) returns(uint d) { return a * 7; }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 a = 0x200030004; testSolidityAgainstCppOnRange(0, [](u256 const& a) -> u256 { return a * 7; }, 0, 100);
BOOST_CHECK(callFunction(0, a) == toBigEndian(a * 7));
} }
BOOST_AUTO_TEST_CASE(empty_contract) BOOST_AUTO_TEST_CASE(empty_contract)
@ -121,7 +160,7 @@ BOOST_AUTO_TEST_CASE(empty_contract)
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes()).empty()); BOOST_CHECK(callContractFunction(0, bytes()).empty());
} }
BOOST_AUTO_TEST_CASE(recursive_calls) BOOST_AUTO_TEST_CASE(recursive_calls)
@ -133,7 +172,7 @@ BOOST_AUTO_TEST_CASE(recursive_calls)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
std::function<u256(u256)> recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256 function<u256(u256)> recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256
{ {
if (n <= 1) if (n <= 1)
return 1; return 1;
@ -141,11 +180,23 @@ BOOST_AUTO_TEST_CASE(recursive_calls)
return n * recursive_calls_cpp(n - 1); return n * recursive_calls_cpp(n - 1);
}; };
BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(0))); testSolidityAgainstCppOnRange(0, recursive_calls_cpp, 0, 5);
BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(1))); }
BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(2)));
BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(3))); BOOST_AUTO_TEST_CASE(multiple_functions)
BOOST_CHECK(testSolidityAgainstCpp(0, recursive_calls_cpp, u256(4))); {
char const* sourceCode = "contract test {\n"
" function a() returns(uint n) { return 0; }\n"
" function b() returns(uint n) { return 1; }\n"
" function c() returns(uint n) { return 2; }\n"
" function f() returns(uint n) { return 3; }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction(0, bytes()) == toBigEndian(u256(0)));
BOOST_CHECK(callContractFunction(1, bytes()) == toBigEndian(u256(1)));
BOOST_CHECK(callContractFunction(2, bytes()) == toBigEndian(u256(2)));
BOOST_CHECK(callContractFunction(3, bytes()) == toBigEndian(u256(3)));
BOOST_CHECK(callContractFunction(4, bytes()) == bytes());
} }
BOOST_AUTO_TEST_CASE(while_loop) BOOST_AUTO_TEST_CASE(while_loop)
@ -169,11 +220,7 @@ BOOST_AUTO_TEST_CASE(while_loop)
return nfac; return nfac;
}; };
BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(0))); testSolidityAgainstCppOnRange(0, while_loop_cpp, 0, 5);
BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(1)));
BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(2)));
BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(3)));
BOOST_CHECK(testSolidityAgainstCpp(0, while_loop_cpp, u256(4)));
} }
BOOST_AUTO_TEST_CASE(break_outside_loop) BOOST_AUTO_TEST_CASE(break_outside_loop)
@ -184,9 +231,8 @@ BOOST_AUTO_TEST_CASE(break_outside_loop)
" break; continue; return 2;\n" " break; continue; return 2;\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode); testSolidityAgainstCpp(0, [](u256 const&) -> u256 { return 2; }, u256(0));
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(2)));
} }
BOOST_AUTO_TEST_CASE(nested_loops) BOOST_AUTO_TEST_CASE(nested_loops)
@ -209,8 +255,7 @@ BOOST_AUTO_TEST_CASE(nested_loops)
" return x;\n" " return x;\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode);
auto nested_loops_cpp = [](u256 n) -> u256 auto nested_loops_cpp = [](u256 n) -> u256
{ {
@ -236,18 +281,7 @@ BOOST_AUTO_TEST_CASE(nested_loops)
return n; return n;
}; };
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(0))); testSolidityAgainstCppOnRange(0, nested_loops_cpp, 0, 12);
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(1)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(2)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(3)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(4)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(5)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(6)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(7)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(8)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(9)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(10)));
BOOST_CHECK(framework.testSolidityAgainstCpp(0, nested_loops_cpp, u256(11)));
} }
BOOST_AUTO_TEST_CASE(calling_other_functions) BOOST_AUTO_TEST_CASE(calling_other_functions)
@ -279,7 +313,8 @@ BOOST_AUTO_TEST_CASE(calling_other_functions)
return 3 * n + 1; return 3 * n + 1;
}; };
auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp] (u256 n) -> u256 { auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp](u256 n) -> u256
{
u256 y; u256 y;
while ((y = n) > 1) while ((y = n) > 1)
{ {
@ -291,11 +326,11 @@ BOOST_AUTO_TEST_CASE(calling_other_functions)
return y; return y;
}; };
BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(0))); testSolidityAgainstCpp(2, collatz_cpp, u256(0));
BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(1))); testSolidityAgainstCpp(2, collatz_cpp, u256(1));
BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(2))); testSolidityAgainstCpp(2, collatz_cpp, u256(2));
BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(8))); testSolidityAgainstCpp(2, collatz_cpp, u256(8));
BOOST_CHECK(testSolidityAgainstCpp(2, collatz_cpp, u256(127))); testSolidityAgainstCpp(2, collatz_cpp, u256(127));
} }
BOOST_AUTO_TEST_CASE(many_local_variables) BOOST_AUTO_TEST_CASE(many_local_variables)
@ -308,8 +343,15 @@ BOOST_AUTO_TEST_CASE(many_local_variables)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000))) auto f = [](u256 const& x1, u256 const& x2, u256 const& x3) -> u256
== toBigEndian(u256(0x121121))); {
u256 a = 0x1;
u256 b = 0x10;
u256 c = 0x100;
u256 y = a + b + c + x1 + x2 + x3;
return y + b + x2;
};
testSolidityAgainstCpp(0, f, u256(0x1000), u256(0x10000), u256(0x100000));
} }
BOOST_AUTO_TEST_CASE(packing_unpacking_types) BOOST_AUTO_TEST_CASE(packing_unpacking_types)
@ -322,7 +364,7 @@ BOOST_AUTO_TEST_CASE(packing_unpacking_types)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) BOOST_CHECK(callContractFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0"))
== fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f")); == fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f"));
} }
@ -334,7 +376,7 @@ BOOST_AUTO_TEST_CASE(multiple_return_values)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) BOOST_CHECK(callContractFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0))); == toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0)));
} }
@ -354,8 +396,7 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
return n; return n;
}; };
BOOST_CHECK(testSolidityAgainstCpp(0, short_circuiting_cpp, u256(0))); testSolidityAgainstCppOnRange(0, short_circuiting_cpp, 0, 2);
BOOST_CHECK(testSolidityAgainstCpp(0, short_circuiting_cpp, u256(1)));
} }
BOOST_AUTO_TEST_CASE(high_bits_cleaning) BOOST_AUTO_TEST_CASE(high_bits_cleaning)
@ -375,7 +416,7 @@ BOOST_AUTO_TEST_CASE(high_bits_cleaning)
return 0; return 0;
return x; return x;
}; };
BOOST_CHECK(testSolidityAgainstCpp(0, high_bits_cleaning_cpp)); testSolidityAgainstCpp(0, high_bits_cleaning_cpp);
} }
BOOST_AUTO_TEST_CASE(sign_extension) BOOST_AUTO_TEST_CASE(sign_extension)
@ -395,7 +436,7 @@ BOOST_AUTO_TEST_CASE(sign_extension)
return 0; return 0;
return u256(x) * -1; return u256(x) * -1;
}; };
BOOST_CHECK(testSolidityAgainstCpp(0, sign_extension_cpp)); testSolidityAgainstCpp(0, sign_extension_cpp);
} }
BOOST_AUTO_TEST_CASE(small_unsigned_types) BOOST_AUTO_TEST_CASE(small_unsigned_types)
@ -412,7 +453,7 @@ BOOST_AUTO_TEST_CASE(small_unsigned_types)
uint32_t x = uint32_t(0xffffff) * 0xffffff; uint32_t x = uint32_t(0xffffff) * 0xffffff;
return x / 0x100; return x / 0x100;
}; };
BOOST_CHECK(testSolidityAgainstCpp(0, small_unsigned_types_cpp)); testSolidityAgainstCpp(0, small_unsigned_types_cpp);
} }
BOOST_AUTO_TEST_CASE(small_signed_types) BOOST_AUTO_TEST_CASE(small_signed_types)
@ -427,7 +468,7 @@ BOOST_AUTO_TEST_CASE(small_signed_types)
{ {
return -int32_t(10) * -int64_t(20); return -int32_t(10) * -int64_t(20);
}; };
BOOST_CHECK(testSolidityAgainstCpp(0, small_signed_types_cpp)); testSolidityAgainstCpp(0, small_signed_types_cpp);
} }
BOOST_AUTO_TEST_CASE(state_smoke_test) BOOST_AUTO_TEST_CASE(state_smoke_test)
@ -445,14 +486,14 @@ BOOST_AUTO_TEST_CASE(state_smoke_test)
" }\n" " }\n"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0))); BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0)));
BOOST_CHECK(callFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0))); BOOST_CHECK(callContractFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0)));
BOOST_CHECK(callFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes()); BOOST_CHECK(callContractFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes());
BOOST_CHECK(callFunction(1, bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes()); BOOST_CHECK(callContractFunction(1, bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes());
BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x1234))); BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x1234)));
BOOST_CHECK(callFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0x8765))); BOOST_CHECK(callContractFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0x8765)));
BOOST_CHECK(callFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes()); BOOST_CHECK(callContractFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes());
BOOST_CHECK(callFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3))); BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3)));
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

214
test/solidityJSONInterfaceTest.cpp

@ -0,0 +1,214 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/**
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2014
* Unit tests for the solidity compiler JSON Interface output.
*/
#include <boost/test/unit_test.hpp>
#include <libsolidity/CompilerStack.h>
#include <jsonrpc/json/json.h>
namespace dev
{
namespace solidity
{
namespace test
{
class InterfaceChecker
{
public:
bool checkInterface(std::string const& _code, std::string const& _expectedInterfaceString)
{
m_compilerStack.parse(_code);
std::string generatedInterfaceString = m_compilerStack.getInterface();
Json::Value generatedInterface;
m_reader.parse(generatedInterfaceString, generatedInterface);
Json::Value expectedInterface;
m_reader.parse(_expectedInterfaceString, expectedInterface);
return expectedInterface == generatedInterface;
}
private:
CompilerStack m_compilerStack;
Json::Reader m_reader;
};
BOOST_FIXTURE_TEST_SUITE(SolidityCompilerJSONInterfaceOutput, InterfaceChecker)
BOOST_AUTO_TEST_CASE(basic_test)
{
char const* sourceCode = "contract test {\n"
" function f(uint a) returns(uint d) { return a * 7; }\n"
"}\n";
char const* interface = R"([
{
"name": "f",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_CASE(empty_contract)
{
char const* sourceCode = "contract test {\n"
"}\n";
char const* interface = "[]";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_CASE(multiple_methods)
{
char const* sourceCode = "contract test {\n"
" function f(uint a) returns(uint d) { return a * 7; }\n"
" function g(uint b) returns(uint e) { return b * 8; }\n"
"}\n";
char const* interface = R"([
{
"name": "f",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
},
{
"name": "g",
"inputs": [
{
"name": "b",
"type": "uint256"
}
],
"outputs": [
{
"name": "e",
"type": "uint256"
}
]
}
])";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_CASE(multiple_params)
{
char const* sourceCode = "contract test {\n"
" function f(uint a, uint b) returns(uint d) { return a + b; }\n"
"}\n";
char const* interface = R"([
{
"name": "f",
"inputs": [
{
"name": "a",
"type": "uint256"
},
{
"name": "b",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_CASE(multiple_methods_order)
{
// methods are expected to be in alpabetical order
char const* sourceCode = "contract test {\n"
" function f(uint a) returns(uint d) { return a * 7; }\n"
" function c(uint b) returns(uint e) { return b * 8; }\n"
"}\n";
char const* interface = R"([
{
"name": "c",
"inputs": [
{
"name": "b",
"type": "uint256"
}
],
"outputs": [
{
"name": "e",
"type": "uint256"
}
]
},
{
"name": "f",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_SUITE_END()
}
}
}

38
test/stPreCompiledContractsFiller.json

@ -12,7 +12,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -46,7 +46,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 500 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 500 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -80,7 +80,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 499 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 499 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -114,7 +114,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code": "{ (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) }", "code": "{ [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -148,7 +148,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 1) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 1) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -182,7 +182,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 33 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 65 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) (CALL 1000 1 0 0 97 97 32) [[ 0 ]] (MOD (MLOAD 97) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 33 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 65 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 97 97 32) [[ 0 ]] (MOD (MLOAD 97) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -216,7 +216,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code": "{ (MSTORE 0 0x2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9) (MSTORE 32 27) (MSTORE 64 0x6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a) (MSTORE 96 0x37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4) (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "code": "{ (MSTORE 0 0x2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9) (MSTORE 32 27) (MSTORE 64 0x6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a) (MSTORE 96 0x37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -284,7 +284,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (CALL 500 2 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ [[ 2 ]] (CALL 500 2 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -318,7 +318,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 5 0xf34578907f) (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -352,7 +352,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xf34578907f) (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -386,7 +386,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 100 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -420,7 +420,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 99 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 99 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -454,7 +454,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 500 2 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 500 2 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -522,7 +522,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (CALL 500 3 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ [[ 2 ]] (CALL 500 3 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -556,7 +556,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 5 0xf34578907f) (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -590,7 +590,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xf34578907f) (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -624,7 +624,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 100 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -658,7 +658,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 99 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 99 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -692,7 +692,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000", "balance" : "20000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (CALL 500 3 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 500 3 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {

34
test/state.cpp

@ -122,6 +122,40 @@ BOOST_AUTO_TEST_CASE(stPreCompiledContracts)
dev::test::executeTests("stPreCompiledContracts", "/StateTests", dev::test::doStateTests); dev::test::executeTests("stPreCompiledContracts", "/StateTests", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(stCreateTest)
{
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--createtest")
{
if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
{
cnote << "usage: ./testeth --createtest <PathToConstructor> <PathToDestiny>\n";
return;
}
try
{
cnote << "Populating tests...";
json_spirit::mValue v;
string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1]));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty.");
json_spirit::read_string(s, v);
dev::test::doStateTests(v, true);
writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true)));
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed state test with Exception: " << diagnostic_information(_e));
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed state test with Exception: " << _e.what());
}
}
}
}
BOOST_AUTO_TEST_CASE(userDefinedFileState) BOOST_AUTO_TEST_CASE(userDefinedFileState)
{ {
dev::test::userDefinedTest("--statetest", dev::test::doStateTests); dev::test::userDefinedTest("--statetest", dev::test::doStateTests);

5
windows/LibEthereum.vcxproj

@ -125,6 +125,7 @@
<ClCompile Include="..\libethereum\Transaction.cpp" /> <ClCompile Include="..\libethereum\Transaction.cpp" />
<ClCompile Include="..\libethereum\TransactionQueue.cpp" /> <ClCompile Include="..\libethereum\TransactionQueue.cpp" />
<ClCompile Include="..\libethereum\Utility.cpp" /> <ClCompile Include="..\libethereum\Utility.cpp" />
<ClCompile Include="..\libevmcore\Assembly.cpp" />
<ClCompile Include="..\libevmcore\Instruction.cpp" /> <ClCompile Include="..\libevmcore\Instruction.cpp" />
<ClCompile Include="..\libevm\ExtVMFace.cpp"> <ClCompile Include="..\libevm\ExtVMFace.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@ -145,7 +146,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="..\libevm\_libevm.cpp" /> <ClCompile Include="..\libevm\_libevm.cpp" />
<ClCompile Include="..\liblll\Assembly.cpp" />
<ClCompile Include="..\liblll\CodeFragment.cpp" /> <ClCompile Include="..\liblll\CodeFragment.cpp" />
<ClCompile Include="..\liblll\Compiler.cpp" /> <ClCompile Include="..\liblll\Compiler.cpp" />
<ClCompile Include="..\liblll\CompilerState.cpp" /> <ClCompile Include="..\liblll\CompilerState.cpp" />
@ -341,6 +341,8 @@
<ClInclude Include="..\libethereum\Transaction.h" /> <ClInclude Include="..\libethereum\Transaction.h" />
<ClInclude Include="..\libethereum\TransactionQueue.h" /> <ClInclude Include="..\libethereum\TransactionQueue.h" />
<ClInclude Include="..\libethereum\Utility.h" /> <ClInclude Include="..\libethereum\Utility.h" />
<ClInclude Include="..\libevmcore\Assembly.h" />
<ClInclude Include="..\libevmcore\Exceptions.h" />
<ClInclude Include="..\libevmcore\Instruction.h" /> <ClInclude Include="..\libevmcore\Instruction.h" />
<ClInclude Include="..\libevm\All.h"> <ClInclude Include="..\libevm\All.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@ -367,7 +369,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude> </ClInclude>
<ClInclude Include="..\liblll\All.h" /> <ClInclude Include="..\liblll\All.h" />
<ClInclude Include="..\libevmcore\Assembly.h" />
<ClInclude Include="..\liblll\CodeFragment.h" /> <ClInclude Include="..\liblll\CodeFragment.h" />
<ClInclude Include="..\liblll\Compiler.h" /> <ClInclude Include="..\liblll\Compiler.h" />
<ClInclude Include="..\liblll\CompilerState.h" /> <ClInclude Include="..\liblll\CompilerState.h" />

15
windows/LibEthereum.vcxproj.filters

@ -40,9 +40,6 @@
<ClCompile Include="..\libevmcore\Instruction.cpp"> <ClCompile Include="..\libevmcore\Instruction.cpp">
<Filter>libevmcore</Filter> <Filter>libevmcore</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\liblll\Assembly.cpp">
<Filter>liblll</Filter>
</ClCompile>
<ClCompile Include="..\liblll\CodeFragment.cpp"> <ClCompile Include="..\liblll\CodeFragment.cpp">
<Filter>liblll</Filter> <Filter>liblll</Filter>
</ClCompile> </ClCompile>
@ -202,6 +199,9 @@
<ClCompile Include="..\libethereum\Account.cpp"> <ClCompile Include="..\libethereum\Account.cpp">
<Filter>libethereum</Filter> <Filter>libethereum</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\libevmcore\Assembly.cpp">
<Filter>libevmcore</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="stdafx.h"> <ClInclude Include="stdafx.h">
@ -248,9 +248,6 @@
</ClInclude> </ClInclude>
<ClInclude Include="..\liblll\All.h"> <ClInclude Include="..\liblll\All.h">
<Filter>liblll</Filter> <Filter>liblll</Filter>
</ClInclude>
<ClInclude Include="..\libevmcore\Assembly.h">
<Filter>libevmcore</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\liblll\CodeFragment.h"> <ClInclude Include="..\liblll\CodeFragment.h">
<Filter>liblll</Filter> <Filter>liblll</Filter>
@ -435,6 +432,12 @@
<ClInclude Include="..\libethereum\Account.h"> <ClInclude Include="..\libethereum\Account.h">
<Filter>libethereum</Filter> <Filter>libethereum</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\libevmcore\Exceptions.h">
<Filter>libevmcore</Filter>
</ClInclude>
<ClInclude Include="..\libevmcore\Assembly.h">
<Filter>libevmcore</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Windows"> <Filter Include="Windows">

Loading…
Cancel
Save