mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'upstream/develop' into evmjit
This commit is contained in:
commit
7fb437d0da
@ -16,6 +16,21 @@ include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(${CRYPTOPP_INCLUDE_DIRS})
|
||||
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
|
||||
|
||||
# search for test names and create ctest tests
|
||||
enable_testing()
|
||||
foreach(file ${SRC_LIST})
|
||||
file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/${file} test_list_raw REGEX "BOOST_.*TEST_(SUITE|CASE)")
|
||||
set(TestSuite "DEFAULT")
|
||||
foreach(test_raw ${test_list_raw})
|
||||
string(REGEX REPLACE ".*TEST_(SUITE|CASE)\\(([^ ,\\)]*).*" "\\1 \\2" test ${test_raw})
|
||||
if(test MATCHES "^SUITE .*")
|
||||
string(SUBSTRING ${test} 6 -1 TestSuite)
|
||||
elseif(test MATCHES "^CASE .*")
|
||||
string(SUBSTRING ${test} 5 -1 TestCase)
|
||||
add_test(NAME ${TestSuite}/${TestCase} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth -t ${TestSuite}/${TestCase})
|
||||
endif(test MATCHES "^SUITE .*")
|
||||
endforeach(test_raw)
|
||||
endforeach(file)
|
||||
|
||||
file(GLOB HEADERS "*.h")
|
||||
add_executable(testeth ${SRC_LIST} ${HEADERS})
|
||||
@ -30,6 +45,7 @@ target_link_libraries(testeth ethereum)
|
||||
target_link_libraries(testeth ethcore)
|
||||
target_link_libraries(testeth secp256k1)
|
||||
target_link_libraries(testeth solidity)
|
||||
target_link_libraries(testeth testutils)
|
||||
if (NOT HEADLESS AND NOT JUSTTESTS)
|
||||
target_link_libraries(testeth webthree)
|
||||
target_link_libraries(testeth natspec)
|
||||
@ -42,13 +58,36 @@ endif()
|
||||
target_link_libraries(createRandomVMTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
|
||||
target_link_libraries(createRandomVMTest ethereum)
|
||||
target_link_libraries(createRandomVMTest ethcore)
|
||||
target_link_libraries(createRandomVMTest testutils)
|
||||
target_link_libraries(createRandomStateTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
|
||||
target_link_libraries(createRandomStateTest ethereum)
|
||||
target_link_libraries(createRandomStateTest ethcore)
|
||||
target_link_libraries(createRandomStateTest testutils)
|
||||
target_link_libraries(checkRandomVMTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
|
||||
target_link_libraries(checkRandomVMTest ethereum)
|
||||
target_link_libraries(checkRandomVMTest ethcore)
|
||||
target_link_libraries(checkRandomVMTest testutils)
|
||||
target_link_libraries(checkRandomStateTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
|
||||
target_link_libraries(checkRandomStateTest ethereum)
|
||||
target_link_libraries(checkRandomStateTest ethcore)
|
||||
target_link_libraries(checkRandomStateTest testutils)
|
||||
|
||||
enable_testing()
|
||||
set(CTEST_OUTPUT_ON_FAILURE TRUE)
|
||||
|
||||
include(EthUtils)
|
||||
|
||||
eth_add_test(ClientBase
|
||||
ARGS --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=1
|
||||
ARGS --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=3
|
||||
ARGS --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=10
|
||||
ARGS --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=1
|
||||
ARGS --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=3
|
||||
ARGS --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=10
|
||||
)
|
||||
|
||||
eth_add_test(JsonRpc
|
||||
ARGS --eth_testfile=BlockTests/bcJS_API_Test
|
||||
ARGS --eth_testfile=BlockTests/bcValidBlockTest
|
||||
)
|
||||
|
||||
|
202
ClientBase.cpp
Normal file
202
ClientBase.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
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 ClientBase.cpp
|
||||
* @author Marek Kotewicz <marek@ethdev.com>
|
||||
* @date 2015
|
||||
*/
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <libdevcore/CommonJS.h>
|
||||
#include "TestUtils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
using namespace dev::test;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(ClientBase, ParallelClientBaseFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(blocks)
|
||||
{
|
||||
enumerateClients([](Json::Value const& _json, dev::eth::ClientBase& _client) -> void
|
||||
{
|
||||
for (string const& name: _json["postState"].getMemberNames())
|
||||
{
|
||||
Json::Value o = _json["postState"][name];
|
||||
Address address(name);
|
||||
|
||||
// balanceAt
|
||||
u256 expectedBalance = u256(o["balance"].asString());
|
||||
u256 balance = _client.balanceAt(address);
|
||||
ETH_CHECK_EQUAL(expectedBalance, balance);
|
||||
|
||||
// countAt
|
||||
u256 expectedCount = u256(o["nonce"].asString());
|
||||
u256 count = _client.countAt(address);
|
||||
ETH_CHECK_EQUAL(expectedCount, count);
|
||||
|
||||
// stateAt
|
||||
for (string const& pos: o["storage"].getMemberNames())
|
||||
{
|
||||
u256 expectedState = u256(o["storage"][pos].asString());
|
||||
u256 state = _client.stateAt(address, u256(pos));
|
||||
ETH_CHECK_EQUAL(expectedState, state);
|
||||
}
|
||||
|
||||
// codeAt
|
||||
bytes expectedCode = fromHex(o["code"].asString());
|
||||
bytes code = _client.codeAt(address);
|
||||
ETH_CHECK_EQUAL_COLLECTIONS(expectedCode.begin(), expectedCode.end(),
|
||||
code.begin(), code.end());
|
||||
}
|
||||
|
||||
// number
|
||||
unsigned expectedNumber = _json["blocks"].size();
|
||||
unsigned number = _client.number();
|
||||
ETH_CHECK_EQUAL(expectedNumber, number);
|
||||
|
||||
u256 totalDifficulty = u256(_json["genesisBlockHeader"]["difficulty"].asString());
|
||||
for (Json::Value const& block: _json["blocks"])
|
||||
{
|
||||
Json::Value blockHeader = block["blockHeader"];
|
||||
Json::Value uncles = block["uncleHeaders"];
|
||||
Json::Value transactions = block["transactions"];
|
||||
h256 blockHash = h256(fromHex(blockHeader["hash"].asString()));
|
||||
|
||||
// just update the difficulty
|
||||
for (Json::Value const& uncle: uncles)
|
||||
{
|
||||
totalDifficulty += u256(uncle["difficulty"].asString());
|
||||
}
|
||||
|
||||
// hashFromNumber
|
||||
h256 expectedHashFromNumber = h256(fromHex(blockHeader["hash"].asString()));
|
||||
h256 hashFromNumber = _client.hashFromNumber(jsToInt(blockHeader["number"].asString()));
|
||||
ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber);
|
||||
|
||||
// blockInfo
|
||||
auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void
|
||||
{
|
||||
LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString()));
|
||||
Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString()));
|
||||
u256 expectedBlockInfoDifficulty = u256(_b["difficulty"].asString());
|
||||
bytes expectedBlockInfoExtraData = fromHex(_b["extraData"].asString());
|
||||
u256 expectedBlockInfoGasLimit = u256(_b["gasLimit"].asString());
|
||||
u256 expectedBlockInfoGasUsed = u256(_b["gasUsed"].asString());
|
||||
h256 expectedBlockInfoHash = h256(fromHex(_b["hash"].asString()));
|
||||
h256 expectedBlockInfoMixHash = h256(fromHex(_b["mixHash"].asString()));
|
||||
Nonce expectedBlockInfoNonce = Nonce(fromHex(_b["nonce"].asString()));
|
||||
u256 expectedBlockInfoNumber = u256(_b["number"].asString());
|
||||
h256 expectedBlockInfoParentHash = h256(fromHex(_b["parentHash"].asString()));
|
||||
h256 expectedBlockInfoReceiptsRoot = h256(fromHex(_b["receiptTrie"].asString()));
|
||||
u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString());
|
||||
h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString()));
|
||||
h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString()));
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty);
|
||||
ETH_CHECK_EQUAL_COLLECTIONS(expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(),
|
||||
_blockInfo.extraData.begin(), _blockInfo.extraData.end());
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot);
|
||||
ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles);
|
||||
};
|
||||
|
||||
BlockInfo blockInfo = _client.blockInfo(blockHash);
|
||||
compareBlockInfos(blockHeader, blockInfo);
|
||||
|
||||
// blockDetails
|
||||
unsigned expectedBlockDetailsNumber = jsToInt(blockHeader["number"].asString());
|
||||
totalDifficulty += u256(blockHeader["difficulty"].asString());
|
||||
BlockDetails blockDetails = _client.blockDetails(blockHash);
|
||||
ETH_CHECK_EQUAL(expectedBlockDetailsNumber, blockDetails.number);
|
||||
ETH_CHECK_EQUAL(totalDifficulty, blockDetails.totalDifficulty);
|
||||
|
||||
auto compareTransactions = [](Json::Value const& _t, Transaction _transaction) -> void
|
||||
{
|
||||
bytes expectedTransactionData = fromHex(_t["data"].asString());
|
||||
u256 expectedTransactionGasLimit = u256(_t["gasLimit"].asString());
|
||||
u256 expectedTransactionGasPrice = u256(_t["gasPrice"].asString());
|
||||
u256 expectedTransactionNonce = u256(_t["nonce"].asString());
|
||||
u256 expectedTransactionSignatureR = h256(fromHex(_t["r"].asString()));
|
||||
u256 expectedTransactionSignatureS = h256(fromHex(_t["s"].asString()));
|
||||
// unsigned expectedTransactionSignatureV = jsToInt(t["v"].asString());
|
||||
|
||||
ETH_CHECK_EQUAL_COLLECTIONS(expectedTransactionData.begin(), expectedTransactionData.end(),
|
||||
_transaction.data().begin(), _transaction.data().end());
|
||||
ETH_CHECK_EQUAL(expectedTransactionGasLimit, _transaction.gas());
|
||||
ETH_CHECK_EQUAL(expectedTransactionGasPrice, _transaction.gasPrice());
|
||||
ETH_CHECK_EQUAL(expectedTransactionNonce, _transaction.nonce());
|
||||
ETH_CHECK_EQUAL(expectedTransactionSignatureR, _transaction.signature().r);
|
||||
ETH_CHECK_EQUAL(expectedTransactionSignatureS, _transaction.signature().s);
|
||||
// ETH_CHECK_EQUAL(expectedTransactionSignatureV, _transaction.signature().v); // 27 === 0x0, 28 === 0x1, not sure why
|
||||
};
|
||||
|
||||
Transactions ts = _client.transactions(blockHash);
|
||||
TransactionHashes tHashes = _client.transactionHashes(blockHash);
|
||||
unsigned tsCount = _client.transactionCount(blockHash);
|
||||
|
||||
ETH_REQUIRE(transactions.size() == ts.size());
|
||||
ETH_REQUIRE(transactions.size() == tHashes.size());
|
||||
|
||||
// transactionCount
|
||||
ETH_CHECK_EQUAL(transactions.size(), tsCount);
|
||||
|
||||
for (unsigned i = 0; i < tsCount; i++)
|
||||
{
|
||||
Json::Value t = transactions[i];
|
||||
|
||||
// transaction (by block hash and transaction index)
|
||||
Transaction transaction = _client.transaction(blockHash, i);
|
||||
compareTransactions(t, transaction);
|
||||
|
||||
// transaction (by hash)
|
||||
Transaction transactionByHash = _client.transaction(transaction.sha3());
|
||||
compareTransactions(t, transactionByHash);
|
||||
|
||||
// transactions
|
||||
compareTransactions(t, ts[i]);
|
||||
|
||||
// transactionHashes
|
||||
ETH_CHECK_EQUAL(transaction.sha3(), tHashes[i]);
|
||||
}
|
||||
|
||||
// uncleCount
|
||||
unsigned usCount = _client.uncleCount(blockHash);
|
||||
ETH_CHECK_EQUAL(uncles.size(), usCount);
|
||||
|
||||
for (unsigned i = 0; i < usCount; i++)
|
||||
{
|
||||
Json::Value u = uncles[i];
|
||||
|
||||
// uncle (by hash)
|
||||
BlockInfo uncle = _client.uncle(blockHash, i);
|
||||
compareBlockInfos(u, uncle);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
@ -28,6 +28,7 @@
|
||||
#include <libsolidity/Parser.h>
|
||||
#include <libsolidity/NameAndTypeResolver.h>
|
||||
#include <libsolidity/Exceptions.h>
|
||||
#include <libsolidity/GlobalContext.h>
|
||||
#include "TestHelper.h"
|
||||
|
||||
using namespace std;
|
||||
@ -48,16 +49,28 @@ ASTPointer<SourceUnit> parseTextAndResolveNames(std::string const& _source)
|
||||
ASTPointer<SourceUnit> sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
|
||||
NameAndTypeResolver resolver({});
|
||||
resolver.registerDeclarations(*sourceUnit);
|
||||
std::shared_ptr<GlobalContext> globalContext = make_shared<GlobalContext>();
|
||||
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
globalContext->setCurrentContract(*contract);
|
||||
resolver.updateDeclaration(*globalContext->getCurrentThis());
|
||||
resolver.updateDeclaration(*globalContext->getCurrentSuper());
|
||||
resolver.resolveNamesAndTypes(*contract);
|
||||
}
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
globalContext->setCurrentContract(*contract);
|
||||
resolver.updateDeclaration(*globalContext->getCurrentThis());
|
||||
resolver.checkTypeRequirements(*contract);
|
||||
}
|
||||
|
||||
return sourceUnit;
|
||||
}
|
||||
|
||||
|
||||
static ContractDefinition const* retrieveContract(ASTPointer<SourceUnit> _source, unsigned index)
|
||||
{
|
||||
ContractDefinition* contract;
|
||||
@ -346,6 +359,63 @@ BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
|
||||
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_no_implementation)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
char const* text = "contract test {\n"
|
||||
" function functionName(bytes32 input) returns (bytes32 out);\n"
|
||||
"}\n";
|
||||
ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
|
||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->getNodes();
|
||||
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[0].get());
|
||||
BOOST_CHECK(contract);
|
||||
BOOST_CHECK(!contract->isFullyImplemented());
|
||||
BOOST_CHECK(!contract->getDefinedFunctions()[0]->isFullyImplemented());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(abstract_contract)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
char const* text = R"(
|
||||
contract base { function foo(); }
|
||||
contract derived is base { function foo() {} }
|
||||
)";
|
||||
ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
|
||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->getNodes();
|
||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[0].get());
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||
BOOST_CHECK(base);
|
||||
BOOST_CHECK(!base->isFullyImplemented());
|
||||
BOOST_CHECK(!base->getDefinedFunctions()[0]->isFullyImplemented());
|
||||
BOOST_CHECK(derived);
|
||||
BOOST_CHECK(derived->isFullyImplemented());
|
||||
BOOST_CHECK(derived->getDefinedFunctions()[0]->isFullyImplemented());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_abstract_contract)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
char const* text = R"(
|
||||
contract base { function foo(); }
|
||||
contract derived {
|
||||
base b;
|
||||
function foo() { b = new base();}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
char const* text = R"(
|
||||
contract base { function foo(); }
|
||||
contract derived is base { function foo() {} }
|
||||
contract wrong is derived { function foo(); }
|
||||
)";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
@ -359,7 +429,7 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
auto functions = contract->getDefinedFunctions();
|
||||
BOOST_CHECK_EQUAL("foo(uint256,uint64,bool)", functions[0]->getCanonicalSignature());
|
||||
BOOST_CHECK_EQUAL("foo(uint256,uint64,bool)", functions[0]->externalSignature());
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,10 +446,95 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
auto functions = contract->getDefinedFunctions();
|
||||
BOOST_CHECK_EQUAL("boo(uint256,bytes32,address)", functions[0]->getCanonicalSignature());
|
||||
if (functions.empty())
|
||||
continue;
|
||||
BOOST_CHECK_EQUAL("boo(uint256,bytes32,address)", functions[0]->externalSignature());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_external_types)
|
||||
{
|
||||
ASTPointer<SourceUnit> sourceUnit;
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
uint a;
|
||||
}
|
||||
contract Test {
|
||||
function boo(uint arg2, bool arg3, bytes8 arg4, bool[2] pairs, uint[] dynamic, C carg) external returns (uint ret) {
|
||||
ret = 5;
|
||||
}
|
||||
})";
|
||||
ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
|
||||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
{
|
||||
auto functions = contract->getDefinedFunctions();
|
||||
if (functions.empty())
|
||||
continue;
|
||||
BOOST_CHECK_EQUAL("boo(uint256,bool,bytes8,bool[2],uint256[],address)", functions[0]->externalSignature());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {}
|
||||
contract Test {
|
||||
function externalCall() {
|
||||
C arg;
|
||||
this.g(arg);
|
||||
}
|
||||
function g (C c) external {}
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_external_call_not_allowed_conversion)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {}
|
||||
contract Test {
|
||||
function externalCall() {
|
||||
address arg;
|
||||
this.g(arg);
|
||||
}
|
||||
function g (C c) external {}
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_internal_allowed_conversion)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
uint a;
|
||||
}
|
||||
contract Test {
|
||||
C a;
|
||||
function g (C c) {}
|
||||
function internalCall() {
|
||||
g(a);
|
||||
}
|
||||
})";
|
||||
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_internal_not_allowed_conversion)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
uint a;
|
||||
}
|
||||
contract Test {
|
||||
address a;
|
||||
function g (C c) {}
|
||||
function internalCall() {
|
||||
g(a);
|
||||
}
|
||||
})";
|
||||
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(hash_collision_in_interface)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
|
@ -176,7 +176,6 @@ BOOST_AUTO_TEST_CASE(dev_and_user_no_doc)
|
||||
"}\n";
|
||||
|
||||
char const* devNatspec = "{\"methods\":{}}";
|
||||
|
||||
char const* userNatspec = "{\"methods\":{}}";
|
||||
|
||||
checkNatspec(sourceCode, devNatspec, false);
|
||||
@ -230,6 +229,18 @@ BOOST_AUTO_TEST_CASE(dev_multiple_params)
|
||||
checkNatspec(sourceCode, natspec, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_documenting_nonexistant_param)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
" /// @dev Multiplies a number by 7 and adds second parameter\n"
|
||||
" /// @param a Documentation for the first parameter\n"
|
||||
" /// @param not_existing Documentation for the second parameter\n"
|
||||
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
|
||||
"}\n";
|
||||
|
||||
BOOST_CHECK_THROW(checkNatspec(sourceCode, "", false), DocstringParsingError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_mutiline_param_description)
|
||||
{
|
||||
char const* sourceCode = "contract test {\n"
|
||||
@ -487,17 +498,7 @@ BOOST_AUTO_TEST_CASE(dev_title_at_function_error)
|
||||
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
|
||||
"}\n";
|
||||
|
||||
char const* natspec = "{"
|
||||
" \"author\": \"Lefteris\","
|
||||
" \"title\": \"Just a test contract\","
|
||||
" \"methods\":{"
|
||||
" \"mul(uint256,uint256)\":{ \n"
|
||||
" \"details\": \"Mul function\"\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}";
|
||||
|
||||
BOOST_CHECK_THROW(checkNatspec(sourceCode, natspec, false), DocstringParsingError);
|
||||
BOOST_CHECK_THROW(checkNatspec(sourceCode, "", false), DocstringParsingError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(natspec_notice_without_tag)
|
||||
|
@ -26,8 +26,11 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <test/solidityExecutionFramework.h>
|
||||
#include <libevmcore/CommonSubexpressionEliminator.h>
|
||||
#include <libevmcore/Assembly.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev::eth;
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -41,16 +44,21 @@ class OptimizerTestFramework: public ExecutionFramework
|
||||
public:
|
||||
OptimizerTestFramework() { }
|
||||
/// Compiles the source code with and without optimizing.
|
||||
void compileBothVersions(unsigned _expectedSizeDecrease, std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") {
|
||||
void compileBothVersions(
|
||||
std::string const& _sourceCode,
|
||||
u256 const& _value = 0,
|
||||
std::string const& _contractName = ""
|
||||
)
|
||||
{
|
||||
m_optimize = false;
|
||||
bytes nonOptimizedBytecode = compileAndRun(_sourceCode, _value, _contractName);
|
||||
m_nonOptimizedContract = m_contractAddress;
|
||||
m_optimize = true;
|
||||
bytes optimizedBytecode = compileAndRun(_sourceCode, _value, _contractName);
|
||||
int sizeDiff = nonOptimizedBytecode.size() - optimizedBytecode.size();
|
||||
BOOST_CHECK_MESSAGE(sizeDiff == int(_expectedSizeDecrease), "Bytecode shrank by "
|
||||
+ boost::lexical_cast<string>(sizeDiff) + " bytes, expected: "
|
||||
+ boost::lexical_cast<string>(_expectedSizeDecrease));
|
||||
BOOST_CHECK_MESSAGE(
|
||||
nonOptimizedBytecode.size() > optimizedBytecode.size(),
|
||||
"Optimizer did not reduce bytecode size."
|
||||
);
|
||||
m_optimizedContract = m_contractAddress;
|
||||
}
|
||||
|
||||
@ -66,6 +74,14 @@ public:
|
||||
"\nOptimized: " + toHex(optimizedOutput));
|
||||
}
|
||||
|
||||
void checkCSE(AssemblyItems const& _input, AssemblyItems const& _expectation)
|
||||
{
|
||||
eth::CommonSubexpressionEliminator cse;
|
||||
BOOST_REQUIRE(cse.feedItems(_input.begin(), _input.end()) == _input.end());
|
||||
AssemblyItems output = cse.getOptimizedItems();
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(_expectation.begin(), _expectation.end(), output.begin(), output.end());
|
||||
}
|
||||
|
||||
protected:
|
||||
Address m_optimizedContract;
|
||||
Address m_nonOptimizedContract;
|
||||
@ -81,24 +97,11 @@ BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
return a;
|
||||
}
|
||||
})";
|
||||
compileBothVersions(29, sourceCode);
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("f(uint256)", u256(7));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(large_integers)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function f() returns (uint a, uint b) {
|
||||
a = 0x234234872642837426347000000;
|
||||
b = 0x10000000000000000000000002;
|
||||
}
|
||||
})";
|
||||
compileBothVersions(36, sourceCode);
|
||||
compareVersions("f()");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(invariants)
|
||||
BOOST_AUTO_TEST_CASE(identities)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
@ -106,7 +109,7 @@ BOOST_AUTO_TEST_CASE(invariants)
|
||||
return int(0) | (int(1) * (int(0) ^ (0 + a)));
|
||||
}
|
||||
})";
|
||||
compileBothVersions(41, sourceCode);
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("f(uint256)", u256(0x12334664));
|
||||
}
|
||||
|
||||
@ -120,7 +123,7 @@ BOOST_AUTO_TEST_CASE(unused_expressions)
|
||||
data;
|
||||
}
|
||||
})";
|
||||
compileBothVersions(36, sourceCode);
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("f()");
|
||||
}
|
||||
|
||||
@ -135,10 +138,171 @@ BOOST_AUTO_TEST_CASE(constant_folding_both_sides)
|
||||
return 98 ^ (7 * ((1 | (x | 1000)) * 40) ^ 102);
|
||||
}
|
||||
})";
|
||||
compileBothVersions(37, sourceCode);
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("f(uint256)");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(storage_access)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
uint8[40] data;
|
||||
function f(uint x) returns (uint y) {
|
||||
data[2] = data[7] = uint8(x);
|
||||
data[4] = data[2] * 10 + data[3];
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("f(uint256)");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(array_copy)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
bytes2[] data1;
|
||||
bytes5[] data2;
|
||||
function f(uint x) returns (uint l, uint y) {
|
||||
for (uint i = 0; i < msg.data.length; ++i)
|
||||
data1[i] = msg.data[i];
|
||||
data2 = data1;
|
||||
l = data2.length;
|
||||
y = uint(data2[x]);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("f(uint256)", 0);
|
||||
compareVersions("f(uint256)", 10);
|
||||
compareVersions("f(uint256)", 36);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_calls)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function f1(uint x) returns (uint) { return x*x; }
|
||||
function f(uint x) returns (uint) { return f1(7+x) - this.f1(x**9); }
|
||||
}
|
||||
)";
|
||||
compileBothVersions(sourceCode);
|
||||
compareVersions("f(uint256)", 0);
|
||||
compareVersions("f(uint256)", 10);
|
||||
compareVersions("f(uint256)", 36);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_intermediate_swap)
|
||||
{
|
||||
eth::CommonSubexpressionEliminator cse;
|
||||
AssemblyItems input{
|
||||
Instruction::SWAP1, Instruction::POP, Instruction::ADD, u256(0), Instruction::SWAP1,
|
||||
Instruction::SLOAD, Instruction::SWAP1, u256(100), Instruction::EXP, Instruction::SWAP1,
|
||||
Instruction::DIV, u256(0xff), Instruction::AND
|
||||
};
|
||||
BOOST_REQUIRE(cse.feedItems(input.begin(), input.end()) == input.end());
|
||||
AssemblyItems output = cse.getOptimizedItems();
|
||||
BOOST_CHECK(!output.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_negative_stack_access)
|
||||
{
|
||||
AssemblyItems input{Instruction::DUP2, u256(0)};
|
||||
checkCSE(input, input);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_negative_stack_end)
|
||||
{
|
||||
AssemblyItems input{Instruction::ADD};
|
||||
checkCSE(input, input);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_intermediate_negative_stack)
|
||||
{
|
||||
AssemblyItems input{Instruction::ADD, u256(1), Instruction::DUP1};
|
||||
checkCSE(input, input);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_pop)
|
||||
{
|
||||
checkCSE({Instruction::POP}, {Instruction::POP});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_unneeded_items)
|
||||
{
|
||||
AssemblyItems input{
|
||||
Instruction::ADD,
|
||||
Instruction::SWAP1,
|
||||
Instruction::POP,
|
||||
u256(7),
|
||||
u256(8),
|
||||
};
|
||||
checkCSE(input, input);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_constant_addition)
|
||||
{
|
||||
AssemblyItems input{u256(7), u256(8), Instruction::ADD};
|
||||
checkCSE(input, {u256(7 + 8)});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_invariants)
|
||||
{
|
||||
AssemblyItems input{
|
||||
Instruction::DUP1,
|
||||
Instruction::DUP1,
|
||||
u256(0),
|
||||
Instruction::OR,
|
||||
Instruction::OR
|
||||
};
|
||||
checkCSE(input, {Instruction::DUP1});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_subself)
|
||||
{
|
||||
checkCSE({Instruction::DUP1, Instruction::SUB}, {Instruction::POP, u256(0)});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_subother)
|
||||
{
|
||||
checkCSE({Instruction::SUB}, {Instruction::SUB});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_double_negation)
|
||||
{
|
||||
checkCSE({Instruction::DUP5, Instruction::NOT, Instruction::NOT}, {Instruction::DUP5});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_associativity)
|
||||
{
|
||||
AssemblyItems input{
|
||||
Instruction::DUP1,
|
||||
Instruction::DUP1,
|
||||
u256(0),
|
||||
Instruction::OR,
|
||||
Instruction::OR
|
||||
};
|
||||
checkCSE(input, {Instruction::DUP1});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cse_associativity2)
|
||||
{
|
||||
AssemblyItems input{
|
||||
u256(0),
|
||||
Instruction::DUP2,
|
||||
u256(2),
|
||||
u256(1),
|
||||
Instruction::DUP6,
|
||||
Instruction::ADD,
|
||||
u256(2),
|
||||
Instruction::ADD,
|
||||
Instruction::ADD,
|
||||
Instruction::ADD,
|
||||
Instruction::ADD
|
||||
};
|
||||
checkCSE(input, {Instruction::DUP2, Instruction::DUP2, Instruction::ADD, u256(5), Instruction::ADD});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -108,6 +108,14 @@ BOOST_AUTO_TEST_CASE(single_function_param)
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_no_body)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
" function functionName(bytes32 input) returns (bytes32 out);\n"
|
||||
"}\n";
|
||||
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_parameter_name_in_named_args)
|
||||
{
|
||||
char const* text = "contract test {\n"
|
||||
|
@ -375,22 +375,6 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e
|
||||
}
|
||||
}
|
||||
|
||||
std::string getTestPath()
|
||||
{
|
||||
string testPath;
|
||||
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
|
||||
|
||||
if (ptestPath == NULL)
|
||||
{
|
||||
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
|
||||
testPath = "../../../tests";
|
||||
}
|
||||
else
|
||||
testPath = ptestPath;
|
||||
|
||||
return testPath;
|
||||
}
|
||||
|
||||
void userDefinedTest(string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests)
|
||||
{
|
||||
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "JsonSpiritHeaders.h"
|
||||
#include <libethereum/State.h>
|
||||
#include <libevm/ExtVMFace.h>
|
||||
#include <libtestutils/Common.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
@ -138,7 +139,6 @@ void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs);
|
||||
void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates);
|
||||
|
||||
void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests);
|
||||
std::string getTestPath();
|
||||
void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests);
|
||||
RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj);
|
||||
eth::LastHashes lastHashes(u256 _currentBlockNumber);
|
||||
|
117
TestUtils.cpp
Normal file
117
TestUtils.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
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 TestUtils.cpp
|
||||
* @author Marek Kotewicz <marek@ethdev.com>
|
||||
* @date 2015
|
||||
*/
|
||||
|
||||
#include <thread>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <libtestutils/BlockChainLoader.h>
|
||||
#include <libtestutils/FixedClient.h>
|
||||
#include "TestUtils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::eth;
|
||||
using namespace dev::test;
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
|
||||
bool getCommandLineOption(std::string const& _name);
|
||||
std::string getCommandLineArgument(std::string const& _name, bool _require = false);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool dev::test::getCommandLineOption(string const& _name)
|
||||
{
|
||||
auto argc = boost::unit_test::framework::master_test_suite().argc;
|
||||
auto argv = boost::unit_test::framework::master_test_suite().argv;
|
||||
bool result = false;
|
||||
for (auto i = 0; !result && i < argc; ++i)
|
||||
result = _name == argv[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string dev::test::getCommandLineArgument(string const& _name, bool _require)
|
||||
{
|
||||
auto argc = boost::unit_test::framework::master_test_suite().argc;
|
||||
auto argv = boost::unit_test::framework::master_test_suite().argv;
|
||||
for (auto i = 1; i < argc; ++i)
|
||||
{
|
||||
string str = argv[i];
|
||||
if (_name == str.substr(0, _name.size()))
|
||||
return str.substr(str.find("=") + 1);
|
||||
}
|
||||
if (_require)
|
||||
BOOST_ERROR("Failed getting command line argument: " << _name << " from: " << argv);
|
||||
return "";
|
||||
}
|
||||
|
||||
LoadTestFileFixture::LoadTestFileFixture()
|
||||
{
|
||||
m_json = loadJsonFromFile(toTestFilePath(getCommandLineArgument("--eth_testfile")));
|
||||
}
|
||||
|
||||
void ParallelFixture::enumerateThreads(std::function<void()> callback) const
|
||||
{
|
||||
size_t threadsCount = std::stoul(getCommandLineArgument("--eth_threads"), nullptr, 10);
|
||||
|
||||
vector<thread> workers;
|
||||
for (size_t i = 0; i < threadsCount; i++)
|
||||
workers.emplace_back(callback);
|
||||
|
||||
for_each(workers.begin(), workers.end(), [](thread &t)
|
||||
{
|
||||
t.join();
|
||||
});
|
||||
}
|
||||
|
||||
void BlockChainFixture::enumerateBlockchains(std::function<void(Json::Value const&, dev::eth::BlockChain const&, State state)> callback) const
|
||||
{
|
||||
for (string const& name: m_json.getMemberNames())
|
||||
{
|
||||
BlockChainLoader bcl(m_json[name]);
|
||||
callback(m_json[name], bcl.bc(), bcl.state());
|
||||
}
|
||||
}
|
||||
|
||||
void ClientBaseFixture::enumerateClients(std::function<void(Json::Value const&, dev::eth::ClientBase&)> callback) const
|
||||
{
|
||||
enumerateBlockchains([&callback](Json::Value const& _json, BlockChain const& _bc, State _state) -> void
|
||||
{
|
||||
FixedClient client(_bc, _state);
|
||||
callback(_json, client);
|
||||
});
|
||||
}
|
||||
|
||||
void ParallelClientBaseFixture::enumerateClients(std::function<void(Json::Value const&, dev::eth::ClientBase&)> callback) const
|
||||
{
|
||||
ClientBaseFixture::enumerateClients([this, &callback](Json::Value const& _json, dev::eth::ClientBase& _client) -> void
|
||||
{
|
||||
// json is being copied here
|
||||
enumerateThreads([callback, _json, &_client]() -> void
|
||||
{
|
||||
callback(_json, _client);
|
||||
});
|
||||
});
|
||||
}
|
82
TestUtils.h
Normal file
82
TestUtils.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
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 TestUtils.h
|
||||
* @author Marek Kotewicz <marek@ethdev.com>
|
||||
* @date 2015
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <json/json.h>
|
||||
#include <libethereum/BlockChain.h>
|
||||
#include <libethereum/ClientBase.h>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
|
||||
// should be used for multithread tests
|
||||
static SharedMutex x_boostTest;
|
||||
#define ETH_CHECK_EQUAL(x, y) { dev::WriteGuard(x_boostTest); BOOST_CHECK_EQUAL(x, y); }
|
||||
#define ETH_CHECK_EQUAL_COLLECTIONS(xb, xe, yb, ye) { dev::WriteGuard(x_boostTest); BOOST_CHECK_EQUAL_COLLECTIONS(xb, xe, yb, ye); }
|
||||
#define ETH_REQUIRE(x) { dev::WriteGuard(x_boostTest); BOOST_REQUIRE(x); }
|
||||
|
||||
struct LoadTestFileFixture
|
||||
{
|
||||
LoadTestFileFixture();
|
||||
|
||||
protected:
|
||||
Json::Value m_json;
|
||||
};
|
||||
|
||||
struct ParallelFixture
|
||||
{
|
||||
void enumerateThreads(std::function<void()> callback) const;
|
||||
};
|
||||
|
||||
struct BlockChainFixture: public LoadTestFileFixture
|
||||
{
|
||||
void enumerateBlockchains(std::function<void(Json::Value const&, dev::eth::BlockChain const&, dev::eth::State state)> callback) const;
|
||||
};
|
||||
|
||||
struct ClientBaseFixture: public BlockChainFixture
|
||||
{
|
||||
void enumerateClients(std::function<void(Json::Value const&, dev::eth::ClientBase&)> callback) const;
|
||||
};
|
||||
|
||||
// important BOOST TEST do have problems with thread safety!!!
|
||||
// BOOST_CHECK is not thread safe
|
||||
// BOOST_MESSAGE is not thread safe
|
||||
// http://boost.2283326.n4.nabble.com/Is-boost-test-thread-safe-td3471644.html
|
||||
// http://lists.boost.org/boost-users/2010/03/57691.php
|
||||
// worth reading
|
||||
// https://codecrafter.wordpress.com/2012/11/01/c-unit-test-framework-adapter-part-3/
|
||||
struct ParallelClientBaseFixture: public ClientBaseFixture, public ParallelFixture
|
||||
{
|
||||
void enumerateClients(std::function<void(Json::Value const&, dev::eth::ClientBase&)> callback) const;
|
||||
};
|
||||
|
||||
struct JsonRpcFixture: public ClientBaseFixture
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@ -20,7 +20,9 @@
|
||||
* block test functions.
|
||||
*/
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <libdevcrypto/FileSystem.h>
|
||||
#include <libtestutils/TransientDirectory.h>
|
||||
#include <libethereum/CanonBlockChain.h>
|
||||
#include "TestHelper.h"
|
||||
|
||||
@ -35,8 +37,8 @@ bytes createBlockRLPFromFields(mObject& _tObj);
|
||||
void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj);
|
||||
BlockInfo constructBlock(mObject& _o);
|
||||
void updatePoW(BlockInfo& _bi);
|
||||
void writeBlockHeaderToJson(mObject& _o, const BlockInfo& _bi);
|
||||
RLPStream createFullBlockFromHeader(const BlockInfo& _bi, const bytes& _txs = RLPEmptyList, const bytes& _uncles = RLPEmptyList);
|
||||
void writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi);
|
||||
RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList);
|
||||
|
||||
void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
|
||||
{
|
||||
@ -75,7 +77,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
|
||||
o["genesisRLP"] = "0x" + toHex(rlpGenesisBlock.out());
|
||||
|
||||
// construct blockchain
|
||||
BlockChain bc(rlpGenesisBlock.out(), string(), true);
|
||||
TransientDirectory td;
|
||||
BlockChain bc(rlpGenesisBlock.out(), td.path(), true);
|
||||
|
||||
if (_fillin)
|
||||
{
|
||||
@ -182,18 +185,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
|
||||
Transactions txList;
|
||||
for (auto const& txi: txs.transactions())
|
||||
{
|
||||
Transaction tx(txi.second, CheckSignature::Sender);
|
||||
txList.push_back(tx);
|
||||
txList.push_back(txi.second);
|
||||
mObject txObject;
|
||||
txObject["nonce"] = toString(tx.nonce());
|
||||
txObject["data"] = "0x" + toHex(tx.data());
|
||||
txObject["gasLimit"] = toString(tx.gas());
|
||||
txObject["gasPrice"] = toString(tx.gasPrice());
|
||||
txObject["r"] = "0x" + toString(tx.signature().r);
|
||||
txObject["s"] = "0x" + toString(tx.signature().s);
|
||||
txObject["v"] = to_string(tx.signature().v + 27);
|
||||
txObject["to"] = tx.isCreation() ? "" : toString(tx.receiveAddress());
|
||||
txObject["value"] = toString(tx.value());
|
||||
txObject["nonce"] = toString(txi.second.nonce());
|
||||
txObject["data"] = "0x" + toHex(txi.second.data());
|
||||
txObject["gasLimit"] = toString(txi.second.gas());
|
||||
txObject["gasPrice"] = toString(txi.second.gasPrice());
|
||||
txObject["r"] = "0x" + toString(txi.second.signature().r);
|
||||
txObject["s"] = "0x" + toString(txi.second.signature().s);
|
||||
txObject["v"] = to_string(txi.second.signature().v + 27);
|
||||
txObject["to"] = txi.second.isCreation() ? "" : toString(txi.second.receiveAddress());
|
||||
txObject["value"] = toString(txi.second.value());
|
||||
|
||||
txArray.push_back(txObject);
|
||||
}
|
||||
@ -242,6 +244,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
|
||||
|
||||
if (sha3(RLP(state.blockData())[2].data()) != sha3(RLP(block2.out())[2].data()))
|
||||
cnote << "uncle list mismatch\n" << RLP(state.blockData())[2].data() << "\n" << RLP(block2.out())[2].data();
|
||||
|
||||
try
|
||||
{
|
||||
state.sync(bc);
|
||||
@ -293,7 +296,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
|
||||
BOOST_CHECK(blObj.count("uncleHeaders") == 0);
|
||||
continue;
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
cnote << "state sync or block import did throw an exception\n";
|
||||
BOOST_CHECK(blObj.count("blockHeader") == 0);
|
||||
@ -389,7 +392,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
|
||||
|
||||
BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions from rlp and transaction from field do not match");
|
||||
BOOST_CHECK_MESSAGE(txsFromField[i].rlp() == txsFromRlp[i].rlp(), "transactions rlp do not match");
|
||||
|
||||
}
|
||||
|
||||
// check uncle list
|
||||
@ -489,12 +491,12 @@ bytes createBlockRLPFromFields(mObject& _tObj)
|
||||
return rlpStream.out();
|
||||
}
|
||||
|
||||
void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj)
|
||||
void overwriteBlockHeader(BlockInfo& _currentBlockHeader, mObject& _blObj)
|
||||
{
|
||||
if (_blObj["blockHeader"].get_obj().size() != 14)
|
||||
{
|
||||
|
||||
BlockInfo tmp = _current_BlockHeader;
|
||||
BlockInfo tmp = _currentBlockHeader;
|
||||
|
||||
if (_blObj["blockHeader"].get_obj().count("parentHash"))
|
||||
tmp.parentHash = h256(_blObj["blockHeader"].get_obj()["parentHash"].get_str());
|
||||
@ -540,16 +542,16 @@ void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj)
|
||||
|
||||
// find new valid nonce
|
||||
|
||||
if (tmp != _current_BlockHeader)
|
||||
if (tmp != _currentBlockHeader)
|
||||
{
|
||||
_current_BlockHeader = tmp;
|
||||
_currentBlockHeader = tmp;
|
||||
|
||||
ProofOfWork pow;
|
||||
std::pair<MineInfo, Ethash::Proof> ret;
|
||||
while (!ProofOfWork::verify(_current_BlockHeader))
|
||||
while (!ProofOfWork::verify(_currentBlockHeader))
|
||||
{
|
||||
ret = pow.mine(_current_BlockHeader, 1000, true, true);
|
||||
Ethash::assignResult(ret.second, _current_BlockHeader);
|
||||
ret = pow.mine(_currentBlockHeader, 1000, true, true);
|
||||
Ethash::assignResult(ret.second, _currentBlockHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -558,13 +560,12 @@ void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj)
|
||||
// take the blockheader as is
|
||||
const bytes c_blockRLP = createBlockRLPFromFields(_blObj["blockHeader"].get_obj());
|
||||
const RLP c_bRLP(c_blockRLP);
|
||||
_current_BlockHeader.populateFromHeader(c_bRLP, IgnoreNonce);
|
||||
_currentBlockHeader.populateFromHeader(c_bRLP, IgnoreNonce);
|
||||
}
|
||||
}
|
||||
|
||||
BlockInfo constructBlock(mObject& _o)
|
||||
{
|
||||
|
||||
BlockInfo ret;
|
||||
try
|
||||
{
|
||||
@ -601,7 +602,7 @@ void updatePoW(BlockInfo& _bi)
|
||||
_bi.hash = _bi.headerHash(WithNonce);
|
||||
}
|
||||
|
||||
void writeBlockHeaderToJson(mObject& _o, const BlockInfo& _bi)
|
||||
void writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi)
|
||||
{
|
||||
_o["parentHash"] = toString(_bi.parentHash);
|
||||
_o["uncleHash"] = toString(_bi.sha3Uncles);
|
||||
@ -621,7 +622,7 @@ void writeBlockHeaderToJson(mObject& _o, const BlockInfo& _bi)
|
||||
_o["hash"] = toString(_bi.hash);
|
||||
}
|
||||
|
||||
RLPStream createFullBlockFromHeader(const BlockInfo& _bi,const bytes& _txs, const bytes& _uncles )
|
||||
RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs, bytes const& _uncles)
|
||||
{
|
||||
RLPStream rlpStream;
|
||||
_bi.streamRLP(rlpStream, WithNonce);
|
||||
@ -633,8 +634,8 @@ RLPStream createFullBlockFromHeader(const BlockInfo& _bi,const bytes& _txs, cons
|
||||
|
||||
return ret;
|
||||
}
|
||||
} }// Namespace Close
|
||||
|
||||
} }// Namespace Close
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(BlockChainTests)
|
||||
|
||||
|
@ -83,12 +83,11 @@ bool doStateTest(mValue& _v)
|
||||
ImportTest importer(o, false);
|
||||
|
||||
eth::State theState = importer.m_statePre;
|
||||
bytes tx = importer.m_transaction.rlp();
|
||||
bytes output;
|
||||
|
||||
try
|
||||
{
|
||||
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output;
|
||||
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
|
||||
}
|
||||
catch (Exception const& _e)
|
||||
{
|
||||
|
@ -183,12 +183,11 @@ void doStateTests(json_spirit::mValue& _v)
|
||||
test::ImportTest importer(o, true);
|
||||
|
||||
eth::State theState = importer.m_statePre;
|
||||
bytes tx = importer.m_transaction.rlp();
|
||||
bytes output;
|
||||
|
||||
try
|
||||
{
|
||||
output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), tx).output;
|
||||
output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
|
||||
}
|
||||
catch (Exception const& _e)
|
||||
{
|
||||
|
38
net.cpp
38
net.cpp
@ -145,7 +145,41 @@ public:
|
||||
bool success = false;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(badPingNodePacket)
|
||||
BOOST_AUTO_TEST_CASE(isIPAddressType)
|
||||
{
|
||||
string wildcard = "0.0.0.0";
|
||||
BOOST_REQUIRE(bi::address::from_string(wildcard).is_unspecified());
|
||||
|
||||
string empty = "";
|
||||
BOOST_REQUIRE_THROW(bi::address::from_string(empty).is_unspecified(), std::exception);
|
||||
|
||||
string publicAddress192 = "192.169.0.0";
|
||||
BOOST_REQUIRE(isPublicAddress(publicAddress192));
|
||||
BOOST_REQUIRE(!isPrivateAddress(publicAddress192));
|
||||
BOOST_REQUIRE(!isLocalHostAddress(publicAddress192));
|
||||
|
||||
string publicAddress172 = "172.32.0.0";
|
||||
BOOST_REQUIRE(isPublicAddress(publicAddress172));
|
||||
BOOST_REQUIRE(!isPrivateAddress(publicAddress172));
|
||||
BOOST_REQUIRE(!isLocalHostAddress(publicAddress172));
|
||||
|
||||
string privateAddress192 = "192.168.1.0";
|
||||
BOOST_REQUIRE(isPrivateAddress(privateAddress192));
|
||||
BOOST_REQUIRE(!isPublicAddress(privateAddress192));
|
||||
BOOST_REQUIRE(!isLocalHostAddress(privateAddress192));
|
||||
|
||||
string privateAddress172 = "172.16.0.0";
|
||||
BOOST_REQUIRE(isPrivateAddress(privateAddress172));
|
||||
BOOST_REQUIRE(!isPublicAddress(privateAddress172));
|
||||
BOOST_REQUIRE(!isLocalHostAddress(privateAddress172));
|
||||
|
||||
string privateAddress10 = "10.0.0.0";
|
||||
BOOST_REQUIRE(isPrivateAddress(privateAddress10));
|
||||
BOOST_REQUIRE(!isPublicAddress(privateAddress10));
|
||||
BOOST_REQUIRE(!isLocalHostAddress(privateAddress10));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(v2PingNodePacket)
|
||||
{
|
||||
// test old versino of pingNode packet w/new
|
||||
RLPStream s;
|
||||
@ -153,7 +187,7 @@ BOOST_AUTO_TEST_CASE(badPingNodePacket)
|
||||
|
||||
PingNode p((bi::udp::endpoint()));
|
||||
BOOST_REQUIRE_NO_THROW(p = PingNode::fromBytesConstRef(bi::udp::endpoint(), bytesConstRef(&s.out())));
|
||||
BOOST_REQUIRE(p.version == 0);
|
||||
BOOST_REQUIRE(p.version == 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_neighbours_packet)
|
||||
|
14
peer.cpp
14
peer.cpp
@ -35,8 +35,8 @@ BOOST_AUTO_TEST_CASE(host)
|
||||
auto oldLogVerbosity = g_logVerbosity;
|
||||
g_logVerbosity = 10;
|
||||
|
||||
NetworkPreferences host1prefs(30301, "127.0.0.1", false, true);
|
||||
NetworkPreferences host2prefs(30302, "127.0.0.1", false, true);
|
||||
NetworkPreferences host1prefs("127.0.0.1", 30301, false);
|
||||
NetworkPreferences host2prefs("127.0.0.1", 30302, false);
|
||||
|
||||
Host host1("Test", host1prefs);
|
||||
host1.start();
|
||||
@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(host)
|
||||
auto node2 = host2.id();
|
||||
host2.start();
|
||||
|
||||
host1.addNode(node2, "127.0.0.1", host2prefs.listenPort, host2prefs.listenPort);
|
||||
host1.addNode(node2, bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort);
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(3));
|
||||
|
||||
@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(save_nodes)
|
||||
std::list<Host*> hosts;
|
||||
for (auto i:{0,1,2,3,4,5})
|
||||
{
|
||||
Host* h = new Host("Test", NetworkPreferences(30300 + i, "127.0.0.1", false, true));
|
||||
Host* h = new Host("Test", NetworkPreferences("127.0.0.1", 30300 + i, false));
|
||||
h->setIdealPeerCount(10);
|
||||
// starting host is required so listenport is available
|
||||
h->start();
|
||||
@ -73,11 +73,11 @@ BOOST_AUTO_TEST_CASE(save_nodes)
|
||||
|
||||
Host& host = *hosts.front();
|
||||
for (auto const& h: hosts)
|
||||
host.addNode(h->id(), "127.0.0.1", h->listenPort(), h->listenPort());
|
||||
host.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort());
|
||||
|
||||
Host& host2 = *hosts.back();
|
||||
for (auto const& h: hosts)
|
||||
host2.addNode(h->id(), "127.0.0.1", h->listenPort(), h->listenPort());
|
||||
host2.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort());
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(2000));
|
||||
bytes firstHostNetwork(host.saveNetwork());
|
||||
@ -122,7 +122,7 @@ int peerTest(int argc, char** argv)
|
||||
Host ph("Test", NetworkPreferences(listenPort));
|
||||
|
||||
if (!remoteHost.empty() && !remoteAlias)
|
||||
ph.addNode(remoteAlias, remoteHost, remotePort, remotePort);
|
||||
ph.addNode(remoteAlias, bi::address::from_string(remoteHost), remotePort, remotePort);
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
|
||||
|
@ -142,7 +142,8 @@ protected:
|
||||
try
|
||||
{
|
||||
// this will throw since the transaction is invalid, but it should nevertheless store the transaction
|
||||
executive.setup(&transactionRLP);
|
||||
executive.initialize(&transactionRLP);
|
||||
executive.execute();
|
||||
}
|
||||
catch (...) {}
|
||||
if (_isCreation)
|
||||
|
@ -53,13 +53,12 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
|
||||
ImportTest importer(o, _fillin);
|
||||
|
||||
State theState = importer.m_statePre;
|
||||
bytes tx = importer.m_transaction.rlp();
|
||||
bytes output;
|
||||
|
||||
try
|
||||
{
|
||||
Listener::ExecTimeGuard guard{i.first};
|
||||
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), tx).output;
|
||||
output = theState.execute(lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output;
|
||||
}
|
||||
catch (Exception const& _e)
|
||||
{
|
||||
|
@ -79,13 +79,9 @@ BOOST_AUTO_TEST_CASE(Complex)
|
||||
cout << s;
|
||||
|
||||
// Inject a transaction to transfer funds from miner to me.
|
||||
bytes tx;
|
||||
{
|
||||
Transaction t(1000, 10000, 10000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
|
||||
assert(t.sender() == myMiner.address());
|
||||
tx = t.rlp();
|
||||
}
|
||||
s.execute(bc, tx);
|
||||
Transaction t(1000, 10000, 10000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
|
||||
assert(t.sender() == myMiner.address());
|
||||
s.execute(bc.lastHashes(), t);
|
||||
|
||||
cout << s;
|
||||
|
||||
|
@ -48,6 +48,13 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
|
||||
if (!txFromRlp.signature().isValid())
|
||||
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
|
||||
}
|
||||
catch(Exception const& _e)
|
||||
{
|
||||
cnote << i.first;
|
||||
cnote << "Transaction Exception: " << diagnostic_information(_e);
|
||||
BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!");
|
||||
continue;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!");
|
||||
|
@ -571,6 +571,7 @@
|
||||
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
|
||||
}
|
||||
},
|
||||
|
||||
"unpadedRValue": {
|
||||
"transaction": {
|
||||
"nonce": "13",
|
||||
@ -583,5 +584,19 @@
|
||||
"v": "28",
|
||||
"value": ""
|
||||
}
|
||||
},
|
||||
|
||||
"libsecp256k1test": {
|
||||
"transaction": {
|
||||
"nonce": "",
|
||||
"gasPrice": "0x09184e72a000",
|
||||
"gasLimit": "0x1388",
|
||||
"to": "",
|
||||
"data": "",
|
||||
"r": "44",
|
||||
"s": "4",
|
||||
"v": "27",
|
||||
"value": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user