diff --git a/CodingStandards.txt b/CodingStandards.txt index e1313e2fd..672a20958 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -72,8 +72,8 @@ All other entities' first alpha is lower case. 4. Variable prefixes: a. Leading underscore "_" to parameter names (both normal and template). -- Exception: "o_parameterName" when it is used exclusively for output. See 7(f). -- Exception: "io_parameterName" when it is used for both input and output. See 7(f). +- Exception: "o_parameterName" when it is used exclusively for output. See 6(f). +- Exception: "io_parameterName" when it is used for both input and output. See 6(f). b. Leading "c_" to const variables (unless part of an external API). c. Leading "g_" to global (non-const) variables. d. Leading "s_" to static (non-const, non-global) variables. diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 482a63cfc..6d57bf2b2 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -22,6 +22,7 @@ #include "Common.h" #include #include +#include "EC.h" #include "SHA3.h" using namespace std; using namespace dev; @@ -108,16 +109,20 @@ KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _pass return KeyPair(sha3(aesDecrypt(_seed, _password))); } -void dev::encrypt(Public _k, bytesConstRef _plain, bytes& _cipher) +void dev::encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher) { - (void)_k; - _cipher = _plain.toBytes(); + bytes io = _plain.toBytes(); + crypto::encrypt(_k, io); + o_cipher = std::move(io); } -bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& _plain) +bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext) { - (void)_k; - _plain = _cipher.toBytes(); + bytes io = _cipher.toBytes(); + crypto::decrypt(_k, io); + if (io.empty()) + return false; + o_plaintext = std::move(io); return true; } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 9d642201a..7f2a8192e 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -57,9 +57,16 @@ using Secrets = h256s; /// @returns 0 if it's not a valid secret key. Address toAddress(Secret _secret); +/// Encrypts plain text using Public key. void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); -bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plain); + +/// Decrypts cipher using Secret key. +bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); + +/// Recovers Public key from signed message. Public recover(Signature _sig, h256 _message); + +/// Returns siganture of message hash. Signature sign(Secret _k, h256 _message); /// Simple class that represents a "key pair". diff --git a/libdevcrypto/CryptoHeaders.h b/libdevcrypto/CryptoHeaders.h deleted file mode 100644 index 333c03a2f..000000000 --- a/libdevcrypto/CryptoHeaders.h +++ /dev/null @@ -1,43 +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 . -*/ -/** @file CryptoHeaders.h - * @author Tim Hughes - * @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" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" -#pragma GCC diagnostic ignored "-Wextra" -#include -#include -#include -#include -#include -#include -#include -#include -#pragma warning(pop) -#pragma GCC diagnostic pop diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp new file mode 100644 index 000000000..cabcfd45a --- /dev/null +++ b/libdevcrypto/CryptoPP.cpp @@ -0,0 +1,74 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file CryptoPP.cpp + * @author Alex Leverington + * @date 2014 + */ + +#include "CryptoPP.h" + +using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; + +ECP::Point pp::PointFromPublic(Public const& _p) +{ + ECP::Point p; + CryptoPP::DL_PublicKey_EC pub; + pub.AccessGroupParameters().Initialize(pp::secp256k1()); + + bytes prefixedKey(pub.GetGroupParameters().GetEncodedElementSize(true)); + prefixedKey[0] = 0x04; + assert(Public::size == prefixedKey.size() - 1); + memcpy(&prefixedKey[1], _p.data(), prefixedKey.size() - 1); + + pub.GetGroupParameters().GetCurve().DecodePoint(p, prefixedKey.data(), prefixedKey.size()); + return std::move(p); +} + +Integer pp::ExponentFromSecret(Secret const& _s) +{ + static_assert(Secret::size == 32, "Secret key must be 32 bytes."); + return std::move(Integer(_s.data(), Secret::size)); +} + +void pp::PublicFromExponent(Integer const& _e, Public& _p) +{ + CryptoPP::DL_PrivateKey_EC k; + k.AccessGroupParameters().Initialize(secp256k1()); + k.SetPrivateExponent(_e); + + CryptoPP::DL_PublicKey_EC p; + p.AccessGroupParameters().Initialize(secp256k1()); + k.MakePublicKey(p); + pp::PublicFromDL_PublicKey_EC(p, _p); +} + +void pp::PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) +{ + bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); + _k.GetGroupParameters().GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); + + static_assert(Public::size == 64, "Public key must be 64 bytes."); + assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); + memcpy(_p.data(), &prefixedKey[1], Public::size); +} + +void pp::SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) +{ + _k.GetPrivateExponent().Encode(_s.data(), Secret::size); +} diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h new file mode 100644 index 000000000..d7e4181ee --- /dev/null +++ b/libdevcrypto/CryptoPP.h @@ -0,0 +1,85 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file CryptoPP.h + * @author Alex Leverington + * @date 2014 + * + * CryptoPP headers and helper methods + */ + +#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 "-Wunused-function" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic ignored "-Wextra" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(pop) +#pragma GCC diagnostic pop +#include "Common.h" + +namespace dev +{ +namespace crypto +{ + +namespace pp +{ +/// RNG used by CryptoPP +inline CryptoPP::AutoSeededRandomPool& PRNG() { static CryptoPP::AutoSeededRandomPool prng; return prng; } + +/// EC curve used by CryptoPP +inline CryptoPP::OID const& secp256k1() { static CryptoPP::OID curve = CryptoPP::ASN1::secp256k1(); return curve; } + +/// Conversion from bytes to cryptopp point +CryptoPP::ECP::Point PointFromPublic(Public const& _p); + +/// Conversion from bytes to cryptopp exponent +CryptoPP::Integer ExponentFromSecret(Secret const& _s); + +/// Conversion from cryptopp exponent Integer to bytes +void PublicFromExponent(CryptoPP::Integer const& _k, Public& _s); + +/// Conversion from cryptopp public key to bytes +void PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); + +/// Conversion from cryptopp private key to bytes +void SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s); + +} +} +} + diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp new file mode 100644 index 000000000..b38703ac3 --- /dev/null +++ b/libdevcrypto/EC.cpp @@ -0,0 +1,73 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file EC.cpp + * @author Alex Leverington + * @date 2014 + * + * Shared EC classes and functions. + */ + +#pragma warning(push) +#pragma warning(disable:4100 4244) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic ignored "-Wextra" +#include +#pragma warning(pop) +#pragma GCC diagnostic pop +#include "CryptoPP.h" +#include "SHA3.h" +#include "EC.h" + +// CryptoPP and dev conflict so dev and pp namespace are used explicitly +using namespace std; +using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; + +void dev::crypto::encrypt(Public const& _key, bytes& io_cipher) +{ + ECIES::Encryptor e; + e.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); + e.AccessKey().SetPublicElement(pp::PointFromPublic(_key)); + size_t plen = io_cipher.size(); + bytes c; + c.resize(e.CiphertextLength(plen)); + // todo: use StringSource with _plain as input and output. + e.Encrypt(pp::PRNG(), io_cipher.data(), plen, c.data()); + bzero(io_cipher.data(), io_cipher.size()); + io_cipher = std::move(c); +} + +void dev::crypto::decrypt(Secret const& _k, bytes& io_text) +{ + CryptoPP::ECIES::Decryptor d; + d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); + d.AccessKey().SetPrivateExponent(pp::ExponentFromSecret(_k)); + size_t clen = io_text.size(); + bytes p; + p.resize(d.MaxPlaintextLength(io_text.size())); + // todo: use StringSource with _c as input and output. + DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data()); + assert(r.messageLength); + io_text.resize(r.messageLength); + io_text = std::move(p); +} + diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h new file mode 100644 index 000000000..cf6714faf --- /dev/null +++ b/libdevcrypto/EC.h @@ -0,0 +1,41 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file EC.h + * @author Alex Leverington + * @date 2014 + * + * Shared EC classes and functions. + */ + +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace crypto +{ + +/// Encrypts text (in place). +void encrypt(Public const& _k, bytes& io_cipher); + +/// Decrypts text (in place). +void decrypt(Secret const& _k, bytes& io_text); + +} +} + diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index d72f5bbd4..b3a6e5955 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -20,7 +20,7 @@ */ #include "SHA3.h" -#include "CryptoHeaders.h" +#include "CryptoPP.h" using namespace std; using namespace dev; diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp new file mode 100644 index 000000000..5c74edd7e --- /dev/null +++ b/libdevcrypto/SHA3MAC.cpp @@ -0,0 +1,39 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file SHA3MAC.cpp + * @author Alex Leverington + * @date 2014 + * + * SHA3 MAC + */ + +#include "CryptoPP.h" +#include "SHA3MAC.h" + +using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; + +void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) +{ + CryptoPP::SHA3_256 ctx; + ctx.Update((byte*)_secret.data(), _secret.size()); + ctx.Update((byte*)_plain.data(), _plain.size()); + assert(_output.size() >= 32); + ctx.Final(_output.data()); +} + diff --git a/libdevcrypto/SHA3MAC.h b/libdevcrypto/SHA3MAC.h new file mode 100644 index 000000000..4b2d06eac --- /dev/null +++ b/libdevcrypto/SHA3MAC.h @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file SHA3MAC.h + * @author Alex Leverington + * @date 2014 + * + * SHA3 MAC + */ + +#pragma once + +#include +#include + +namespace dev +{ +namespace crypto +{ + +void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output); + +} +} + diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index 7d3916fd3..bfb8942cc 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include "ProofOfWork.h" using namespace std; diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 15da9e0d8..91b4a42b1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -248,12 +248,16 @@ void Literal::accept(ASTVisitor& _visitor) _visitor.endVisit(*this); } +TypeError ASTNode::createTypeError(std::string const& _description) +{ + return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); +} + void Statement::expectType(Expression& _expression, const Type& _expectedType) { _expression.checkTypeRequirements(); if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type not implicitly convertible " - "to expected type.")); + BOOST_THROW_EXCEPTION(_expression.createTypeError("Type not implicitly convertible to expected type.")); //@todo provide more information to the exception } @@ -287,11 +291,10 @@ void Break::checkTypeRequirements() void Return::checkTypeRequirements() { - BOOST_ASSERT(m_returnParameters != nullptr); + BOOST_ASSERT(m_returnParameters); if (m_returnParameters->getParameters().size() != 1) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Different number of arguments in " - "return statement than in returns " - "declaration.")); + BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " + "than in returns declaration.")); // this could later be changed such that the paramaters type is an anonymous struct type, // but for now, we only allow one return parameter expectType(*m_expression, *m_returnParameters->getParameters().front()->getType()); @@ -327,7 +330,7 @@ void Assignment::checkTypeRequirements() { // complex assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); } } @@ -337,7 +340,7 @@ void UnaryOperation::checkTypeRequirements() m_subExpression->checkTypeRequirements(); m_type = m_subExpression->getType(); if (m_type->acceptsUnaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Unary operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); } void BinaryOperation::checkTypeRequirements() @@ -349,7 +352,7 @@ void BinaryOperation::checkTypeRequirements() else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("No common type found in binary operation.")); + BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); if (Token::isCompareOp(m_operator)) m_type = std::make_shared(); else @@ -357,7 +360,7 @@ void BinaryOperation::checkTypeRequirements() BOOST_ASSERT(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); } } @@ -371,15 +374,14 @@ void FunctionCall::checkTypeRequirements() if (category == Type::Category::TYPE) { TypeType const* type = dynamic_cast(&expressionType); - BOOST_ASSERT(type != nullptr); + BOOST_ASSERT(type); //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("More than one argument for " - "explicit type conersion.")); + BOOST_THROW_EXCEPTION(createTypeError("More than one argument for " + "explicit type conersion.")); if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Explicit type conversion not " - "allowed.")); + BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); m_type = type->getActualType(); } else if (category == Type::Category::FUNCTION) @@ -388,16 +390,14 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters FunctionType const* function = dynamic_cast(&expressionType); - BOOST_ASSERT(function != nullptr); + BOOST_ASSERT(function); FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Wrong argument count for " - "function call.")); + BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Invalid type for argument in " - "function call.")); + BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs if (fun.getReturnParameterList()->getParameters().empty()) @@ -406,9 +406,7 @@ void FunctionCall::checkTypeRequirements() m_type = fun.getReturnParameterList()->getParameters().front()->getType(); } else - { - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type does not support invocation.")); - } + BOOST_THROW_EXCEPTION(createTypeError("Type does not support invocation.")); } void MemberAccess::checkTypeRequirements() @@ -425,7 +423,7 @@ void IndexAccess::checkTypeRequirements() void Identifier::checkTypeRequirements() { - BOOST_ASSERT(m_referencedDeclaration != nullptr); + BOOST_ASSERT(m_referencedDeclaration); //@todo these dynamic casts here are not really nice... // is i useful to have an AST visitor here? // or can this already be done in NameAndTypeResolver? @@ -435,24 +433,24 @@ void Identifier::checkTypeRequirements() // var y = x; // the type of x is not yet determined. VariableDeclaration* variable = dynamic_cast(m_referencedDeclaration); - if (variable != nullptr) + if (variable) { if (!variable->getType()) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Variable referenced before type " - "could be determined.")); + BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type " + "could be determined.")); m_type = variable->getType(); return; } //@todo can we unify these with TypeName::toType()? StructDefinition* structDef = dynamic_cast(m_referencedDeclaration); - if (structDef != nullptr) + if (structDef) { // note that we do not have a struct type here m_type = std::make_shared(std::make_shared(*structDef)); return; } FunctionDefinition* functionDef = dynamic_cast(m_referencedDeclaration); - if (functionDef != nullptr) + if (functionDef) { // a function reference is not a TypeType, because calling a TypeType converts to the type. // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type @@ -461,7 +459,7 @@ void Identifier::checkTypeRequirements() return; } ContractDefinition* contractDef = dynamic_cast(m_referencedDeclaration); - if (contractDef != nullptr) + if (contractDef) { m_type = std::make_shared(std::make_shared(*contractDef)); return; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index d5e1e0662..df146ab10 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -22,16 +22,16 @@ #pragma once -#include #include #include #include - +#include #include #include #include #include +#include namespace dev { @@ -57,6 +57,10 @@ public: Location const& getLocation() const { return m_location; } + /// Creates a @ref TypeError exception and decorates it with the location of the node and + /// the given description + TypeError createTypeError(std::string const& _description); + private: Location m_location; }; @@ -165,7 +169,7 @@ public: Declaration(_location, _name), m_typeName(_type) {} virtual void accept(ASTVisitor& _visitor) override; - bool isTypeGivenExplicitly() const { return m_typeName.get() != nullptr; } + bool isTypeGivenExplicitly() const { return bool(m_typeName); } TypeName* getTypeName() const { return m_typeName.get(); } //! Returns the declared or inferred type. Can be an empty pointer if no type was explicitly diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index c512bd3f9..44245ed46 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -172,6 +172,7 @@ bool ASTPrinter::visit(VariableDefinition& _node) bool ASTPrinter::visit(Expression& _node) { writeLine("Expression"); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -179,6 +180,7 @@ bool ASTPrinter::visit(Expression& _node) bool ASTPrinter::visit(Assignment& _node) { writeLine(std::string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator())); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -187,6 +189,7 @@ bool ASTPrinter::visit(UnaryOperation& _node) { writeLine(std::string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + ") " + Token::toString(_node.getOperator())); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -194,6 +197,7 @@ bool ASTPrinter::visit(UnaryOperation& _node) bool ASTPrinter::visit(BinaryOperation& _node) { writeLine(std::string("BinaryOperation using operator ") + Token::toString(_node.getOperator())); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -201,6 +205,7 @@ bool ASTPrinter::visit(BinaryOperation& _node) bool ASTPrinter::visit(FunctionCall& _node) { writeLine("FunctionCall"); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -208,6 +213,7 @@ bool ASTPrinter::visit(FunctionCall& _node) bool ASTPrinter::visit(MemberAccess& _node) { writeLine("MemberAccess to member " + _node.getMemberName()); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -215,6 +221,7 @@ bool ASTPrinter::visit(MemberAccess& _node) bool ASTPrinter::visit(IndexAccess& _node) { writeLine("IndexAccess"); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -222,6 +229,7 @@ bool ASTPrinter::visit(IndexAccess& _node) bool ASTPrinter::visit(PrimaryExpression& _node) { writeLine("PrimaryExpression"); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -229,6 +237,7 @@ bool ASTPrinter::visit(PrimaryExpression& _node) bool ASTPrinter::visit(Identifier& _node) { writeLine(std::string("Identifier ") + _node.getName()); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -236,6 +245,7 @@ bool ASTPrinter::visit(Identifier& _node) bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) { writeLine(std::string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken())); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -243,9 +253,10 @@ bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) bool ASTPrinter::visit(Literal& _node) { char const* tokenString = Token::toString(_node.getToken()); - if (tokenString == nullptr) + if (!tokenString) tokenString = "[no token]"; writeLine(std::string("Literal, token: ") + tokenString + " value: " + _node.getValue()); + printType(_node); printSourcePart(_node); return goDeeper(); } @@ -406,10 +417,18 @@ void ASTPrinter::printSourcePart(ASTNode const& _node) { Location const& location(_node.getLocation()); *m_ostream << getIndentation() << " Source: |" - << m_source.substr(location.start, location.end - location.start) << "|\n"; + << m_source.substr(location.start, location.end - location.start) << "|" << std::endl; } } +void ASTPrinter::printType(Expression const& _expression) +{ + if (_expression.getType()) + *m_ostream << getIndentation() << " Type: " << _expression.getType()->toString() << "\n"; + else + *m_ostream << getIndentation() << " Type unknown.\n"; +} + std::string ASTPrinter::getIndentation() const { return std::string(m_indentation * 2, ' '); @@ -417,7 +436,7 @@ std::string ASTPrinter::getIndentation() const void ASTPrinter::writeLine(std::string const& _line) { - *m_ostream << getIndentation() << _line << '\n'; + *m_ostream << getIndentation() << _line << std::endl; } } diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index e8d125a54..14592e2b9 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -102,6 +102,7 @@ public: private: void printSourcePart(ASTNode const& _node); + void printType(Expression const& _expression); std::string getIndentation() const; void writeLine(std::string const& _line); bool goDeeper() { m_indentation++; return true; } diff --git a/libsolidity/BaseTypes.h b/libsolidity/BaseTypes.h index fdf3f7b53..cfc14c7e9 100644 --- a/libsolidity/BaseTypes.h +++ b/libsolidity/BaseTypes.h @@ -22,6 +22,7 @@ #pragma once +#include namespace dev { @@ -41,5 +42,11 @@ struct Location int end; }; +/// Stream output for Location (used e.g. in boost exceptions). +inline std::ostream& operator<<(std::ostream& _out, Location const& _location) +{ + return _out << "[" << _location.start << "," << _location.end << ")"; +} + } } diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index c600ebf12..5a48c47dd 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -22,7 +22,9 @@ #pragma once +#include #include +#include namespace dev { @@ -33,5 +35,8 @@ struct ParserError: virtual Exception {}; struct TypeError: virtual Exception {}; struct DeclarationError: virtual Exception {}; +typedef boost::error_info errinfo_sourcePosition; +typedef boost::error_info errinfo_sourceLocation; + } } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 707b6ce14..e9d90dc88 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -129,15 +129,17 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) void DeclarationRegistrationHelper::closeCurrentScope() { - BOOST_ASSERT(m_currentScope != nullptr); + BOOST_ASSERT(m_currentScope); m_currentScope = m_currentScope->getOuterScope(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - BOOST_ASSERT(m_currentScope != nullptr); + BOOST_ASSERT(m_currentScope); if (!m_currentScope->registerDeclaration(_declaration)) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Identifier already declared.")); + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) + << errinfo_comment("Identifier already declared.")); + //@todo the exception should also contain the location of the first declaration if (_opensScope) enterNewSubScope(_declaration); } @@ -153,14 +155,14 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) { // endVisit because the internal type needs resolving if it is a user defined type // or mapping - if (_variable.getTypeName() != nullptr) + if (_variable.getTypeName()) _variable.setType(_variable.getTypeName()->toType()); // otherwise we have a "var"-declaration whose type is resolved by the first assignment } bool ReferencesResolver::visit(Return& _return) { - BOOST_ASSERT(m_returnParameters != nullptr); + BOOST_ASSERT(m_returnParameters); _return.setFunctionReturnParameters(*m_returnParameters); return true; } @@ -174,12 +176,13 @@ bool ReferencesResolver::visit(Mapping&) bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); - if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); + if (!declaration) + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_typeName.getLocation()) + << errinfo_comment("Undeclared identifier.")); StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types - if (referencedStruct == nullptr) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Identifier does not name a type name.")); + if (!referencedStruct) + BOOST_THROW_EXCEPTION(_typeName.createTypeError("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } @@ -187,8 +190,9 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) bool ReferencesResolver::visit(Identifier& _identifier) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); - if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); + if (!declaration) + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation()) + << errinfo_comment("Undeclared identifier.")); _identifier.setReferencedDeclaration(*declaration); return false; } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 408aa7bd6..1ea413ee9 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -106,7 +106,7 @@ ASTPointer Parser::parseContractDefinition() expectToken(Token::SEMICOLON); } else - throwExpectationError("Function, variable or struct declaration expected."); + BOOST_THROW_EXCEPTION(createParserError("Function, variable or struct declaration expected.")); } nodeFactory.markEndPosition(); expectToken(Token::RBRACE); @@ -184,7 +184,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::VAR) { if (!_allowVar) - throwExpectationError("Expected explicit type name."); + BOOST_THROW_EXCEPTION(createParserError("Expected explicit type name.")); m_scanner->next(); } else if (token == Token::MAPPING) @@ -198,7 +198,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) type = nodeFactory.createNode(expectIdentifierToken()); } else - throwExpectationError("Expected type name"); + BOOST_THROW_EXCEPTION(createParserError("Expected type name")); return type; } @@ -208,7 +208,7 @@ ASTPointer Parser::parseMapping() expectToken(Token::MAPPING); expectToken(Token::LPAREN); if (!Token::isElementaryTypeName(m_scanner->getCurrentToken())) - throwExpectationError("Expected elementary type name for mapping key type"); + BOOST_THROW_EXCEPTION(createParserError("Expected elementary type name for mapping key type")); ASTPointer keyType; keyType = ASTNodeFactory(*this).createNode(m_scanner->getCurrentToken()); m_scanner->next(); @@ -481,7 +481,7 @@ ASTPointer Parser::parsePrimaryExpression() } else { - throwExpectationError("Expected primary expression."); + BOOST_THROW_EXCEPTION(createParserError("Expected primary expression.")); return ASTPointer(); // this is not reached } break; @@ -507,7 +507,7 @@ std::vector> Parser::parseFunctionCallArguments() void Parser::expectToken(Token::Value _value) { if (m_scanner->getCurrentToken() != _value) - throwExpectationError(std::string("Expected token ") + std::string(Token::getName(_value))); + BOOST_THROW_EXCEPTION(createParserError(std::string("Expected token ") + std::string(Token::getName(_value)))); m_scanner->next(); } @@ -515,7 +515,7 @@ Token::Value Parser::expectAssignmentOperator() { Token::Value op = m_scanner->getCurrentToken(); if (!Token::isAssignmentOp(op)) - throwExpectationError(std::string("Expected assignment operator")); + BOOST_THROW_EXCEPTION(createParserError("Expected assignment operator")); m_scanner->next(); return op; } @@ -523,7 +523,7 @@ Token::Value Parser::expectAssignmentOperator() ASTPointer Parser::expectIdentifierToken() { if (m_scanner->getCurrentToken() != Token::IDENTIFIER) - throwExpectationError("Expected identifier"); + BOOST_THROW_EXCEPTION(createParserError("Expected identifier")); return getLiteralAndAdvance(); } @@ -534,18 +534,9 @@ ASTPointer Parser::getLiteralAndAdvance() return identifier; } -void Parser::throwExpectationError(std::string const& _description) +ParserError Parser::createParserError(std::string const& _description) const { - //@todo put some of this stuff into ParserError - int line, column; - std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition()); - std::stringstream buf; - buf << "Solidity parser error: " << _description - << " at line " << (line + 1) - << ", column " << (column + 1) << "\n" - << m_scanner->getLineAtPosition(getPosition()) << "\n" - << std::string(column, ' ') << "^"; - BOOST_THROW_EXCEPTION(ParserError() << errinfo_comment(buf.str())); + return ParserError() << errinfo_sourcePosition(getPosition()) << errinfo_comment(_description); } diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 7cc415136..14338dc28 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -73,9 +73,12 @@ private: Token::Value expectAssignmentOperator(); ASTPointer expectIdentifierToken(); ASTPointer getLiteralAndAdvance(); - void throwExpectationError(std::string const& _description); /// @} + /// Creates a @ref ParserError exception and annotates it with the current position and the + /// given @a _description. + ParserError createParserError(std::string const& _description) const; + std::shared_ptr m_scanner; }; diff --git a/libsolidity/Scope.cpp b/libsolidity/Scope.cpp index 28a54dd27..4fcd2f45e 100644 --- a/libsolidity/Scope.cpp +++ b/libsolidity/Scope.cpp @@ -41,7 +41,7 @@ Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const auto result = m_declarations.find(_name); if (result != m_declarations.end()) return result->second; - if (_recursive && m_outerScope != nullptr) + if (_recursive && m_outerScope) return m_outerScope->resolveName(_name, true); return nullptr; } diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp new file mode 100644 index 000000000..b270342c9 --- /dev/null +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -0,0 +1,93 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Formatting functions for errors referencing positions and locations in the source. + */ + +#include +#include +#include + +namespace dev +{ +namespace solidity +{ + +void SourceReferenceFormatter::printSourceLocation(std::ostream& _stream, + Location const& _location, + Scanner const& _scanner) +{ + int startLine; + int startColumn; + std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); + _stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; + int endLine; + int endColumn; + std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); + if (startLine == endLine) + { + _stream << _scanner.getLineAtPosition(_location.start) << std::endl + << std::string(startColumn, ' ') << "^"; + if (endColumn > startColumn + 2) + _stream << std::string(endColumn - startColumn - 2, '-'); + if (endColumn > startColumn + 1) + _stream << "^"; + _stream << std::endl; + } + else + _stream << _scanner.getLineAtPosition(_location.start) << std::endl + << std::string(startColumn, ' ') << "^\n" + << "Spanning multiple lines.\n"; +} + +void SourceReferenceFormatter::printSourcePosition(std::ostream& _stream, + int _position, + const Scanner& _scanner) +{ + int line; + int column; + std::tie(line, column) = _scanner.translatePositionToLineColumn(_position); + _stream << "at line " << (line + 1) << ", column " << (column + 1) << std::endl + << _scanner.getLineAtPosition(_position) << std::endl + << std::string(column, ' ') << "^" << std::endl; +} + +void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, + Exception const& _exception, + std::string const& _name, + Scanner const& _scanner) +{ + _stream << _name; + if (std::string const* description = boost::get_error_info(_exception)) + _stream << ": " << *description; + + if (int const* position = boost::get_error_info(_exception)) + { + _stream << " "; + printSourcePosition(_stream, *position, _scanner); + } + if (Location const* location = boost::get_error_info(_exception)) + { + _stream << " "; + printSourceLocation(_stream, *location, _scanner); + } +} + +} +} diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/SourceReferenceFormatter.h new file mode 100644 index 000000000..4736066fd --- /dev/null +++ b/libsolidity/SourceReferenceFormatter.h @@ -0,0 +1,48 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2014 + * Formatting functions for errors referencing positions and locations in the source. + */ + +#pragma once + +#include +#include + +namespace dev +{ + +class Exception; // forward + +namespace solidity +{ + +class Scanner; // forward + +struct SourceReferenceFormatter +{ +public: + static void printSourceLocation(std::ostream& _stream, Location const& _location, Scanner const& _scanner); + static void printSourcePosition(std::ostream& _stream, int _position, Scanner const& _scanner); + static void printExceptionInformation(std::ostream& _stream, Exception const& _exception, + std::string const& _name, Scanner const& _scanner); +}; + +} +} diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7634951a1..62324f8c2 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -20,6 +20,7 @@ * Solidity data types */ +#include #include #include @@ -88,9 +89,9 @@ std::shared_ptr IntegerType::smallestTypeForLiteral(std::string con IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): m_bits(_bits), m_modifier(_modifier) { - BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0); if (isAddress()) _bits = 160; + BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0); } bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const @@ -130,6 +131,14 @@ bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const return _operator == Token::DELETE || (!isAddress() && _operator == Token::BIT_NOT); } +std::string IntegerType::toString() const +{ + if (isAddress()) + return "address"; + std::string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint"); + return prefix + dev::toString(m_bits); +} + bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const { // conversion to integer is fine, but not to address diff --git a/libsolidity/Types.h b/libsolidity/Types.h index e0c09bdcf..82b549433 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -59,6 +59,8 @@ public: } virtual bool acceptsBinaryOperator(Token::Value) const { return false; } virtual bool acceptsUnaryOperator(Token::Value) const { return false; } + + virtual std::string toString() const = 0; }; class IntegerType: public Type @@ -68,7 +70,7 @@ public: { UNSIGNED, SIGNED, HASH, ADDRESS }; - virtual Category getCategory() const { return Category::INTEGER; } + virtual Category getCategory() const override { return Category::INTEGER; } static std::shared_ptr smallestTypeForLiteral(std::string const& _literal); @@ -79,6 +81,8 @@ public: virtual bool acceptsBinaryOperator(Token::Value _operator) const override; virtual bool acceptsUnaryOperator(Token::Value _operator) const override; + virtual std::string toString() const override; + int getNumBits() const { return m_bits; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } bool isAddress() const { return m_modifier == Modifier::ADDRESS; } @@ -106,15 +110,18 @@ public: { return _operator == Token::NOT || _operator == Token::DELETE; } + virtual std::string toString() const override { return "bool"; } }; class ContractType: public Type { public: - virtual Category getCategory() const { return Category::CONTRACT; } + virtual Category getCategory() const override { return Category::CONTRACT; } ContractType(ContractDefinition const& _contract): m_contract(_contract) {} virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const; + virtual std::string toString() const override { return "contract{...}"; } + private: ContractDefinition const& m_contract; }; @@ -122,7 +129,7 @@ private: class StructType: public Type { public: - virtual Category getCategory() const { return Category::STRUCT; } + virtual Category getCategory() const override { return Category::STRUCT; } StructType(StructDefinition const& _struct): m_struct(_struct) {} virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const; virtual bool acceptsUnaryOperator(Token::Value _operator) const override @@ -130,6 +137,9 @@ public: return _operator == Token::DELETE; } + + virtual std::string toString() const override { return "struct{...}"; } + private: StructDefinition const& m_struct; }; @@ -137,11 +147,13 @@ private: class FunctionType: public Type { public: - virtual Category getCategory() const { return Category::FUNCTION; } + virtual Category getCategory() const override { return Category::FUNCTION; } FunctionType(FunctionDefinition const& _function): m_function(_function) {} FunctionDefinition const& getFunction() const { return m_function; } + virtual std::string toString() const override { return "function(...)returns(...)"; } + private: FunctionDefinition const& m_function; }; @@ -149,8 +161,10 @@ private: class MappingType: public Type { public: - virtual Category getCategory() const { return Category::MAPPING; } + virtual Category getCategory() const override { return Category::MAPPING; } MappingType() {} + virtual std::string toString() const override { return "mapping(...=>...)"; } + private: //@todo }; @@ -159,18 +173,21 @@ private: class VoidType: public Type { public: - virtual Category getCategory() const { return Category::VOID; } + virtual Category getCategory() const override { return Category::VOID; } VoidType() {} + virtual std::string toString() const override { return "void"; } }; class TypeType: public Type { public: - virtual Category getCategory() const { return Category::TYPE; } + virtual Category getCategory() const override { return Category::TYPE; } TypeType(std::shared_ptr const& _actualType): m_actualType(_actualType) {} std::shared_ptr const& getActualType() const { return m_actualType; } + virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } + private: std::shared_ptr m_actualType; }; diff --git a/solc/main.cpp b/solc/main.cpp index e155b0fe6..ba0b6ccf7 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -9,21 +9,11 @@ #include #include #include +#include +#include -namespace dev -{ -namespace solidity -{ - -ASTPointer parseAST(std::string const& _source) -{ - ASTPointer scanner = std::make_shared(CharStream(_source)); - Parser parser; - return parser.parse(scanner); -} - -} -} // end namespaces +using namespace dev; +using namespace solidity; void help() { @@ -57,28 +47,50 @@ int main(int argc, char** argv) else infile = argv[i]; } - std::string src; + std::string sourceCode; if (infile.empty()) { std::string s; while (!std::cin.eof()) { getline(std::cin, s); - src.append(s); + sourceCode.append(s); } } else + sourceCode = asString(dev::contents(infile)); + + ASTPointer ast; + std::shared_ptr scanner = std::make_shared(CharStream(sourceCode)); + Parser parser; + try + { + ast = parser.parse(scanner); + } + catch (ParserError const& exception) + { + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Parser error", *scanner); + return -1; + } + + dev::solidity::NameAndTypeResolver resolver; + try { - src = dev::asString(dev::contents(infile)); + resolver.resolveNamesAndTypes(*ast.get()); } - std::cout << "Parsing..." << std::endl; - // @todo catch exception - dev::solidity::ASTPointer ast = dev::solidity::parseAST(src); + catch (DeclarationError const& exception) + { + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Declaration error", *scanner); + return -1; + } + catch (TypeError const& exception) + { + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Type error", *scanner); + return -1; + } + std::cout << "Syntax tree for the contract:" << std::endl; - dev::solidity::ASTPrinter printer(ast, src); + dev::solidity::ASTPrinter printer(ast, sourceCode); printer.print(std::cout); - std::cout << "Resolving identifiers..." << std::endl; - dev::solidity::NameAndTypeResolver resolver; - resolver.resolveNamesAndTypes(*ast.get()); return 0; } diff --git a/test/TestHelperCrypto.h b/test/TestHelperCrypto.h index cdc22ec31..01e97c21f 100644 --- a/test/TestHelperCrypto.h +++ b/test/TestHelperCrypto.h @@ -21,23 +21,7 @@ #pragma once -//#include - -#pragma warning(push) -#pragma warning(disable:4100 4244) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" -#pragma GCC diagnostic ignored "-Wextra" -#include -#include -#include -#include -#include -#pragma warning(pop) -#pragma GCC diagnostic pop +#include using namespace std; using namespace CryptoPP; diff --git a/test/crypto.cpp b/test/crypto.cpp index e71ee2285..0d3b6202f 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -27,37 +27,163 @@ #include #include #include +#include #include "TestHelperCrypto.h" using namespace std; using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; -namespace dev -{ -namespace crypto +BOOST_AUTO_TEST_SUITE(devcrypto) + +BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) { + string message("Now is the time for all good persons to come to the aide of humanity."); + bytes m = asBytes(message); + bytesConstRef bcr(&m); + + KeyPair k = KeyPair::create(); + bytes cipher; + encrypt(k.pub(), bcr, cipher); + assert(cipher != asBytes(message) && cipher.size() > 0); + + bytes plain; + decrypt(k.sec(), bytesConstRef(&cipher), plain); + + assert(asString(plain) == message); + assert(plain == asBytes(message)); +} -inline CryptoPP::AutoSeededRandomPool& PRNG() { - static CryptoPP::AutoSeededRandomPool prng; - return prng; +BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) +{ + ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Encryptor e(d.GetKey()); + + Secret s; + pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + + Public p; + pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + + assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + + Secret previous = s; + for (auto i = 0; i < 30; i++) + { + ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Encryptor e(d.GetKey()); + + Secret s; + pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + assert(s != previous); + + Public p; + pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + + assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + } } + +BOOST_AUTO_TEST_CASE(cryptopp_keys_cryptor_sipaseckp256k1) +{ + KeyPair k = KeyPair::create(); + Secret s = k.sec(); + + // Convert secret to exponent used by pp + Integer e = pp::ExponentFromSecret(s); + + // Test that exported DL_EC private is same as exponent from Secret + CryptoPP::DL_PrivateKey_EC privatek; + privatek.AccessGroupParameters().Initialize(pp::secp256k1()); + privatek.SetPrivateExponent(e); + assert(e == privatek.GetPrivateExponent()); + // Test that exported secret is same as decryptor(privatek) secret + ECIES::Decryptor d; + d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); + d.AccessKey().SetPrivateExponent(e); + assert(d.AccessKey().GetPrivateExponent() == e); + + // Test that decryptor->encryptor->public == private->makepublic->public + CryptoPP::DL_PublicKey_EC pubk; + pubk.AccessGroupParameters().Initialize(pp::secp256k1()); + privatek.MakePublicKey(pubk); + + ECIES::Encryptor enc(d); + assert(pubk.GetPublicElement() == enc.AccessKey().GetPublicElement()); + + // Test against sipa/seckp256k1 + Public p; + pp::PublicFromExponent(pp::ExponentFromSecret(s), p); + assert(toAddress(s) == dev::right160(dev::sha3(p.ref()))); + assert(k.pub() == p); } + +BOOST_AUTO_TEST_CASE(cryptopp_public_export_import) +{ + ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Encryptor e(d.GetKey()); + + Secret s; + pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + Public p; + pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + Address addr = right160(dev::sha3(p.ref())); + assert(toAddress(s) == addr); + + KeyPair l(s); + assert(l.address() == addr); + + DL_PublicKey_EC pub; + pub.Initialize(pp::secp256k1(), pp::PointFromPublic(p)); + assert(pub.GetPublicElement() == e.GetKey().GetPublicElement()); + + KeyPair k = KeyPair::create(); + Public p2; + pp::PublicFromExponent(pp::ExponentFromSecret(k.sec()), p2); + assert(k.pub() == p2); + + Address a = k.address(); + Address a2 = toAddress(k.sec()); + assert(a2 == a); } -using namespace CryptoPP; +BOOST_AUTO_TEST_CASE(ecies_eckeypair) +{ + KeyPair k = KeyPair::create(); + + string message("Now is the time for all good persons to come to the aide of humanity."); + string original = message; + + bytes b = asBytes(message); + encrypt(k.pub(), b); + assert(b != asBytes(original)); -BOOST_AUTO_TEST_SUITE(crypto) + decrypt(k.sec(), b); + assert(b == asBytes(original)); +} + +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_AUTO_TEST_CASE(cryptopp_ecies_message) { cnote << "Testing cryptopp_ecies_message..."; - string const message("Now is the time for all good men to come to the aide of humanity."); + string const message("Now is the time for all good persons to come to the aide of humanity."); - AutoSeededRandomPool prng; - - ECIES::Decryptor localDecryptor(prng, ASN1::secp256r1()); + ECIES::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1()); SavePrivateKey(localDecryptor.GetPrivateKey()); ECIES::Encryptor localEncryptor(localDecryptor); @@ -65,31 +191,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) ECIES::Decryptor futureDecryptor; LoadPrivateKey(futureDecryptor.AccessPrivateKey()); - futureDecryptor.GetPrivateKey().ThrowIfInvalid(prng, 3); + futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3); ECIES::Encryptor futureEncryptor; LoadPublicKey(futureEncryptor.AccessPublicKey()); - futureEncryptor.GetPublicKey().ThrowIfInvalid(prng, 3); + futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG(), 3); // encrypt/decrypt with local string cipherLocal; - StringSource ss1 (message, true, new PK_EncryptorFilter(prng, localEncryptor, new StringSink(cipherLocal) ) ); + StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG(), localEncryptor, new StringSink(cipherLocal) ) ); string plainLocal; - StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(prng, localDecryptor, new StringSink(plainLocal) ) ); + StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocal) ) ); // encrypt/decrypt with future string cipherFuture; - StringSource ss3 (message, true, new PK_EncryptorFilter(prng, futureEncryptor, new StringSink(cipherFuture) ) ); + StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG(), futureEncryptor, new StringSink(cipherFuture) ) ); string plainFuture; - StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(prng, futureDecryptor, new StringSink(plainFuture) ) ); + StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFuture) ) ); // decrypt local w/future string plainFutureFromLocal; - StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(prng, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); + StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFutureFromLocal) ) ); // decrypt future w/local string plainLocalFromFuture; - StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(prng, localDecryptor, new StringSink(plainLocalFromFuture) ) ); + StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); assert(plainLocal == message); @@ -98,98 +224,112 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) assert(plainLocalFromFuture == plainLocal); } -BOOST_AUTO_TEST_CASE(cryptopp_ecdh_prime) +BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) { - cnote << "Testing cryptopp_ecdh_prime..."; + const int aesKeyLen = 16; + assert(sizeof(char) == sizeof(byte)); - using namespace CryptoPP; - OID curve = ASN1::secp256r1(); - - ECDH::Domain dhLocal(curve); - SecByteBlock privLocal(dhLocal.PrivateKeyLength()); - SecByteBlock pubLocal(dhLocal.PublicKeyLength()); - dhLocal.GenerateKeyPair(dev::crypto::PRNG(), privLocal, pubLocal); + // generate test key + AutoSeededRandomPool rng; + SecByteBlock key(0x00, aesKeyLen); + rng.GenerateBlock(key, key.size()); - ECDH::Domain dhRemote(curve); - SecByteBlock privRemote(dhRemote.PrivateKeyLength()); - SecByteBlock pubRemote(dhRemote.PublicKeyLength()); - dhRemote.GenerateKeyPair(dev::crypto::PRNG(), privRemote, pubRemote); + // cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr + byte ctr[AES::BLOCKSIZE]; + rng.GenerateBlock(ctr, sizeof(ctr)); - assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength()); + string text = "Now is the time for all good persons to come to the aide of humanity."; + // c++11 ftw + unsigned char const* in = (unsigned char*)&text[0]; + unsigned char* out = (unsigned char*)&text[0]; + string original = text; - // local: send public to remote; remote: send public to local + string cipherCopy; + try + { + CTR_Mode::Encryption e; + e.SetKeyWithIV(key, key.size(), ctr); + e.ProcessData(out, in, text.size()); + assert(text != original); + cipherCopy = text; + } + catch(CryptoPP::Exception& e) + { + cerr << e.what() << endl; + } - // Local - SecByteBlock sharedLocal(dhLocal.AgreedValueLength()); - assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote)); + try + { + CTR_Mode< AES >::Decryption d; + d.SetKeyWithIV(key, key.size(), ctr); + d.ProcessData(out, in, text.size()); + assert(text == original); + } + catch(CryptoPP::Exception& e) + { + cerr << e.what() << endl; + } - // 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()); + // reencrypt ciphertext... + try + { + assert(cipherCopy != text); + in = (unsigned char*)&cipherCopy[0]; + out = (unsigned char*)&cipherCopy[0]; + + CTR_Mode::Encryption e; + e.SetKeyWithIV(key, key.size(), ctr); + e.ProcessData(out, in, text.size()); + + // yep, ctr mode. + assert(cipherCopy == original); + } + catch(CryptoPP::Exception& e) + { + cerr << e.what() << endl; + } - assert(ssLocal != 0); - assert(ssLocal == ssRemote); } -BOOST_AUTO_TEST_CASE(cryptopp_ecdh_aes128_cbc_noauth) +BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) { - // ECDH gives 256-bit shared while aes uses 128-bits - // Use first 128-bits of shared secret as symmetric key - // IV is 0 - // New connections require new ECDH keypairs + const int aesKeyLen = 16; + assert(sizeof(char) == sizeof(byte)); + AutoSeededRandomPool rng; + SecByteBlock key(0x00, aesKeyLen); + rng.GenerateBlock(key, key.size()); -} + // Generate random IV + byte iv[AES::BLOCKSIZE]; + rng.GenerateBlock(iv, AES::BLOCKSIZE); -BOOST_AUTO_TEST_CASE(cryptopp_eth_fbba) -{ - // Initial Authentication: - // - // New/Known Peer: - // pubkeyL = knownR? ? myKnown : myECDH - // pubkeyR = knownR? ? theirKnown : theirECDH - // - // Initial message = hmac(k=sha3(shared-secret[128..255]), address(pubkeyL)) || ECIES encrypt(pubkeyR, pubkeyL) - // - // Key Exchange (this could occur after handshake messages): - // If peers do not know each other they will need to exchange public keys. - // - // Drop ECDH (this could occur after handshake messages): - // After authentication and/or key exchange, both sides generate shared key - // from their 'known' keys and use this to encrypt all future messages. - // - // v2: If one side doesn't trust the other then a single-use key maybe sent. - // This will need to be tracked for future connections; when non-trusting peer - // wants to trust the other, it can request that it's old, 'new', public key be - // accepted. And, if the peer *really* doesn't trust the other side, it can request - // that a new, 'new', public key be accepted. - // - // Handshake (all or nothing, padded): - // All Peers (except blacklisted): - // - // - // New Peer: - // - // - // Known Untrusted Peer: - // - // - // Known Trusted Peer: - // - // - // Blacklisted Peeer: - // Already dropped by now. - // - // - // MAC: - // ... -} + string string128("AAAAAAAAAAAAAAAA"); + string plainOriginal = string128; + CryptoPP::CBC_Mode::Encryption cbcEncryption(key, key.size(), iv); + cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); + assert(string128 != plainOriginal); + + CBC_Mode::Decryption cbcDecryption(key, key.size(), iv); + cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); + assert(plainOriginal == string128); + + + // plaintext whose size isn't divisible by block size must use stream filter for padding + string string192("AAAAAAAAAAAAAAAABBBBBBBB"); + plainOriginal = string192; + + string cipher; + StreamTransformationFilter* aesStream = new StreamTransformationFilter(cbcEncryption, new StringSink(cipher)); + StringSource source(string192, true, aesStream); + assert(cipher.size() == 32); + + cbcDecryption.ProcessData((byte*)&cipher[0], (byte*)&string192[0], cipher.size()); + assert(string192 == plainOriginal); +} + BOOST_AUTO_TEST_CASE(eth_keypairs) { cnote << "Testing Crypto..."; diff --git a/test/vmIOandFlowOperationsTestFiller.json b/test/vmIOandFlowOperationsTestFiller.json index 79d162c8d..a470b9c8d 100644 --- a/test/vmIOandFlowOperationsTestFiller.json +++ b/test/vmIOandFlowOperationsTestFiller.json @@ -670,6 +670,34 @@ } }, + "jumpi2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff596002600357", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "pc0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/vmPushDupSwapTestFiller.json b/test/vmPushDupSwapTestFiller.json index 1bb3e6630..52c704d42 100644 --- a/test/vmPushDupSwapTestFiller.json +++ b/test/vmPushDupSwapTestFiller.json @@ -27,6 +27,34 @@ } }, + "push1_missingStack": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "0x60", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, + "push2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/vmSystemOperationsTestFiller.json b/test/vmSystemOperationsTestFiller.json index c948f0436..1df2697e0 100644 --- a/test/vmSystemOperationsTestFiller.json +++ b/test/vmSystemOperationsTestFiller.json @@ -509,7 +509,7 @@ } }, - "CallRecursiveBomb": { + "CallRecursiveBomb0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -543,6 +543,90 @@ } }, + "CallRecursiveBomb1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "1", + "gas" : "364723" + } + }, + + "CallRecursiveBomb2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "1", + "gas" : "364724" + } + }, + + "CallRecursiveBomb3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "20000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (+ (SLOAD 0) 1) [[ 1 ]] (CALL (- (GAS) 224) (ADDRESS) 0 0 0 0 0) }", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "1", + "gas" : "1000000" + } + }, + "suicide0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -949,6 +1033,77 @@ } }, + "ABAcalls2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x945304eb96065b2a98b57a48a06ae28d285a71b5 1 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "0", + "code" : " { [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 0 0 0 0 0) } ", + "nonce" : "0", + "storage" : { + } + } + + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "10000000000000" + } + }, + + "ABAcalls3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1025000", + "nonce" : 0, + "code" : "{ [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x945304eb96065b2a98b57a48a06ae28d285a71b5 1 0 0 0 0) }", + "storage": {} + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "0", + "code" : " { [[ 0 ]] (ADD (SLOAD 0) 1) (CALL (- (GAS) 1000) 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 0 0 0 0 0) } ", + "nonce" : "0", + "storage" : { + } + } + + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "100000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "1000000" + } + }, "ABAcallsSuicide0": { "env" : {