Skip to content

Commit

Permalink
WIP (#21)
Browse files Browse the repository at this point in the history
* WIP

* fix tests

* fix pop_service_tests

* Fixes

* fix mempool tests

* check that CreateNewBlock removes just 1 invalid transaction per block

* Comment failing test

Co-authored-by: Bohdan <[email protected]>
  • Loading branch information
eu321 and Warchant committed Feb 20, 2020
1 parent dd412c9 commit 65c6f7f
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 71 deletions.
2 changes: 1 addition & 1 deletion src/test/util/setup_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ TestingSetup::~TestingSetup()
pblocktree.reset();
}

TestChain100Setup::TestChain100Setup()
TestChain100Setup::TestChain100Setup(): RegTestingSetup()
{
// CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests.
// TODO: fix the code to support SegWit blocks.
Expand Down
5 changes: 5 additions & 0 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2494,6 +2494,8 @@ bool CChainState::DisconnectTip(BlockValidationState& state, const CChainParams&
}
}

VeriBlock::getService<VeriBlock::PopService>().removePayloads(*pindexDelete);

m_chain.SetTip(pindexDelete->pprev);

UpdateTip(pindexDelete->pprev, chainparams);
Expand Down Expand Up @@ -2620,6 +2622,9 @@ bool CChainState::ConnectTip(BlockValidationState& state, const CChainParams& ch
// Remove conflicting transactions from the mempool.;
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
disconnectpool.removeForBlock(blockConnecting.vtx);

VeriBlock::getService<VeriBlock::PopService>().addPayloads(*pindexNew, blockConnecting);

// Update m_chain & related variables.
m_chain.SetTip(pindexNew);
UpdateTip(pindexNew, chainparams);
Expand Down
4 changes: 4 additions & 0 deletions src/vbk/pop_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ struct PopService {
virtual bool determineATVPlausibilityWithBTCRules(AltchainId altChainIdentifier, const CBlockHeader& popEndorsementHeader, const Consensus::Params& params, TxValidationState& state) = 0;

virtual void addPayloads(std::string blockHash, const int& nHeight, const Publications& publications) = 0;
virtual void addPayloads(const CBlockIndex & blockIndex, const CBlock & block) = 0;

virtual void removePayloads(const CBlockIndex & block) = 0;
virtual void removePayloads(std::string blockHash, const int& blockHeight) = 0;

virtual void setConfig() = 0;
};
} // namespace VeriBlock
Expand Down
66 changes: 45 additions & 21 deletions src/vbk/pop_service/pop_service_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,51 @@ void PopServiceImpl::addPayloads(std::string blockHash, const int& nHeight, cons
}
}

void PopServiceImpl::addPayloads(const CBlockIndex & blockIndex, const CBlock & block)
{
std::unique_lock<std::mutex> lock(mutex);
AddPayloadsDataRequest request;

auto* index = new BlockIndex();
index->set_height(blockIndex.nHeight);
index->set_hash(blockIndex.GetBlockHash().ToString());
request.set_allocated_blockindex(index);

for (const auto & tx : block.vtx) {
if (!isPopTx(*tx)) {
continue;
}

Publications publications;
PopTxType type;
ScriptError serror;
assert(parsePopTx(tx, &serror, &publications, nullptr, &type) && "scriptSig of pop tx is invalid in addPayloads");

// skip non-publication transactions
if (type != PopTxType::PUBLICATIONS) {
continue;
}

// insert payloads
request.add_altpublications(publications.atv.data(), publications.atv.size());
for (const auto& vtb : publications.vtbs) {
request.add_veriblockpublications(vtb.data(), vtb.size());
}
}

EmptyReply reply;
ClientContext context;
Status status = grpcPopService->AddPayloads(&context, request, &reply);
if (!status.ok()) {
throw PopServiceException(status);
}
}

void PopServiceImpl::removePayloads(const CBlockIndex & block)
{
removePayloads(block.GetBlockHash().ToString(), block.nHeight);
}

void PopServiceImpl::removePayloads(std::string blockHash, const int& nHeight)
{
std::unique_lock<std::mutex> lock(mutex);
Expand All @@ -155,9 +200,6 @@ void PopServiceImpl::savePopTxToDatabase(const CBlock& block, const int& nHeight
SaveBlockPopTxRequest request;
EmptyReply reply;

AddPayloadsDataRequest payloads;


auto* b1 = new AltChainBlock();
BlockToProtoAltChainBlock(block, nHeight, *b1);
request.set_allocated_containingblock(b1);
Expand All @@ -179,12 +221,6 @@ void PopServiceImpl::savePopTxToDatabase(const CBlock& block, const int& nHeight
continue;
}

// insert payloads
payloads.add_altpublications(publications.atv.data(), publications.atv.size());
for (const auto& vtb : publications.vtbs) {
payloads.add_veriblockpublications(vtb.data(), vtb.size());
}

// Fill the proto objects with pop data
popTxData->set_poptxhash(tx->GetHash().ToString());
popTxData->set_altpublication(publications.atv.data(), publications.atv.size());
Expand Down Expand Up @@ -212,18 +248,6 @@ void PopServiceImpl::savePopTxToDatabase(const CBlock& block, const int& nHeight
}

if (request.popdata_size() != 0) {
// first, addPayloads
{
auto* index = new BlockIndex();
index->set_height(nHeight);
index->set_hash(block.GetHash().ToString());
payloads.set_allocated_blockindex(index);
ClientContext context;
Status status = grpcPopService->AddPayloads(&context, payloads, &reply);
if (!status.ok()) {
throw PopServiceException(status);
}
}
// then, save pop txes to database
{
ClientContext context;
Expand Down
4 changes: 3 additions & 1 deletion src/vbk/pop_service/pop_service_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ class PopServiceImpl : public PopService
bool determineATVPlausibilityWithBTCRules(AltchainId altChainIdentifier, const CBlockHeader& popEndorsementHeader, const Consensus::Params& params, TxValidationState& state) override;

void addPayloads(std::string blockHash, const int& nHeight, const Publications& publications) override;
void addPayloads(const CBlockIndex & blockIndex, const CBlock & block) override;

void removePayloads(std::string blockHash, const int& nHeight) override;
void removePayloads(const CBlockIndex & blockIndex) override;
void removePayloads(std::string blockHash, const int& blockHeight) override;

void setConfig() override;

Expand Down
6 changes: 3 additions & 3 deletions src/vbk/test/unit/block_validation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ struct BlockValidationFixture : public TestChain100Setup {
return VeriBlock::EvalScriptImpl(tx->vin[0].scriptSig, stack, serror, pub, ctx, type, false);
});
When(Method(pop_impl_mock, determineATVPlausibilityWithBTCRules)).AlwaysReturn(true);
Fake(Method(pop_impl_mock, addPayloads));
Fake(Method(pop_impl_mock, removePayloads));
Fake(OverloadedMethod(pop_impl_mock, addPayloads, void(std::string, const int&, const VeriBlock::Publications&)));
Fake(OverloadedMethod(pop_impl_mock, removePayloads, void(std::string, const int&)));
Fake(Method(pop_impl_mock, updateContext));
Fake(Method(pop_impl_mock, clearTemporaryPayloads));

Expand Down Expand Up @@ -122,4 +122,4 @@ BOOST_FIXTURE_TEST_CASE(BlockWithBothPopTxes, BlockValidationFixture)
Verify_Method(Method(pop_impl_mock, updateContext)).Exactly(1);
}

BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
21 changes: 12 additions & 9 deletions src/vbk/test/unit/pop_service_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static CBlock createBlockWithPopTx(TestChain100Setup& test)
inline void setPublicationData(VeriBlock::PublicationData& pub, const CDataStream& stream, const int64_t& index)
{
pub.set_identifier(index);
pub.set_header(stream.data(), stream.size());
pub.set_header((void*)stream.data(), stream.size());
}

struct PopServiceFixture : public TestChain100Setup {
Expand All @@ -36,8 +36,11 @@ struct PopServiceFixture : public TestChain100Setup {
AbortShutdown();
VeriBlock::InitUtilService();
VeriBlock::InitConfig();
Fake(Method(pop_service_impl_mock, addPayloads));
Fake(Method(pop_service_impl_mock, removePayloads));
VeriBlockTest::setUpPopServiceMock(pop_service_mock);
Fake(OverloadedMethod(pop_service_mock, removePayloads, void(const CBlockIndex&)));
Fake(OverloadedMethod(pop_service_impl_mock, addPayloads, void(std::string, const int&, const VeriBlock::Publications&)));
Fake(OverloadedMethod(pop_service_impl_mock, addPayloads, void(const CBlockIndex&, const CBlock&)));
Fake(OverloadedMethod(pop_service_impl_mock, removePayloads, void(std::string, const int&)));
Fake(Method(pop_service_impl_mock, clearTemporaryPayloads));
When(OverloadedMethod(pop_service_impl_mock, parsePopTx, bool(const CTransactionRef&, ScriptError*, VeriBlock::Publications*, VeriBlock::Context*, VeriBlock::PopTxType*)))
.Do([](const CTransactionRef&, ScriptError* serror, VeriBlock::Publications*, VeriBlock::Context*, VeriBlock::PopTxType* type) -> bool {
Expand Down Expand Up @@ -107,7 +110,7 @@ BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_wrong_index, PopServiceFixture)
BOOST_CHECK(!blockPopValidationImpl(pop_service_impl_mock.get(), block, *ChainActive().Tip()->pprev, Params().GetConsensus(), state));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "pop-tx-altchain-id");
}
Verify_Method(Method(pop_service_impl_mock, removePayloads)).Once();
Verify_Method(OverloadedMethod(pop_service_impl_mock, removePayloads, void(std::string, const int&))).Once();
}

BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_endorsed_block_not_known_orphan_block, PopServiceFixture)
Expand All @@ -134,7 +137,7 @@ BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_endorsed_block_not_known_orphan_
BOOST_CHECK(!blockPopValidationImpl(pop_service_impl_mock.get(), block, *ChainActive().Tip()->pprev, Params().GetConsensus(), state));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "pop-tx-endorsed-block-not-known-orphan-block");
}
Verify_Method(Method(pop_service_impl_mock, removePayloads)).Once();
Verify_Method(OverloadedMethod(pop_service_impl_mock, removePayloads, void(std::string, const int&))).Once();
}

BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_endorsed_block_not_from_chain, PopServiceFixture)
Expand Down Expand Up @@ -171,7 +174,7 @@ BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_endorsed_block_not_from_chain, P
BOOST_CHECK(!blockPopValidationImpl(pop_service_impl_mock.get(), block, *ChainActive().Tip()->pprev, Params().GetConsensus(), state));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "pop-tx-endorsed-block-not-from-this-chain");
}
Verify_Method(Method(pop_service_impl_mock, removePayloads)).Once();
Verify_Method(OverloadedMethod(pop_service_impl_mock, removePayloads, void(std::string, const int&))).Once();
}

BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_wrong_settlement_interval, PopServiceFixture)
Expand Down Expand Up @@ -200,7 +203,7 @@ BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_wrong_settlement_interval, PopSe
BOOST_CHECK(!blockPopValidationImpl(pop_service_impl_mock.get(), block, *ChainActive().Tip()->pprev, Params().GetConsensus(), state));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "pop-tx-endorsed-block-too-old");
}
Verify_Method(Method(pop_service_impl_mock, removePayloads)).Once();
Verify_Method(OverloadedMethod(pop_service_impl_mock, removePayloads, void(std::string, const int&))).Once();
}

BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_wrong_addPayloads, PopServiceFixture)
Expand All @@ -220,7 +223,7 @@ BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_wrong_addPayloads, PopServiceFix
setPublicationData(publicationData, stream, config.index.unwrap());
});

When(Method(pop_service_impl_mock, addPayloads)).AlwaysDo([](std::string hash, const int& nHeight, const VeriBlock::Publications& publications) -> void {
When(OverloadedMethod(pop_service_impl_mock, addPayloads, void(std::string, const int&, const VeriBlock::Publications&))).AlwaysDo([](std::string hash, const int& nHeight, const VeriBlock::Publications& publications) -> void {
throw VeriBlock::PopServiceException("fail");
});

Expand All @@ -230,6 +233,6 @@ BOOST_FIXTURE_TEST_CASE(blockPopValidation_test_wrong_addPayloads, PopServiceFix
BOOST_CHECK(!blockPopValidationImpl(pop_service_impl_mock.get(), block, *ChainActive().Tip()->pprev, Params().GetConsensus(), state));
BOOST_CHECK_EQUAL(state.GetRejectReason(), "pop-tx-add-payloads-failed");
}
Verify_Method(Method(pop_service_impl_mock, removePayloads)).Once();
Verify_Method(OverloadedMethod(pop_service_impl_mock, removePayloads, void(std::string, const int&))).Once();
}
BOOST_AUTO_TEST_SUITE_END()
20 changes: 17 additions & 3 deletions src/vbk/test/unit/rpc_service_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,20 @@
#include <vbk/util_service.hpp>

#include <string>
#include <vbk/init.hpp>

UniValue CallRPC(std::string args);

struct RpcServiceFixture : public TestChain100Setup {
VeriBlockTest::ServicesFixture service_fixture;

fakeit::Mock<VeriBlock::PopService> pop_service_mock;

RpcServiceFixture()
{
VeriBlock::InitConfig();
VeriBlockTest::setUpPopServiceMock(pop_service_mock);
}
};

BOOST_FIXTURE_TEST_SUITE(rpc_service_tests, RpcServiceFixture)
Expand All @@ -30,6 +39,8 @@ BOOST_AUTO_TEST_CASE(getpopdata_test)
auto chain = interfaces::MakeChain(node);
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
AddWallet(wallet);
node.connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
VeriBlock::InitRpcService(node.connman.get());

int blockHeight = 10;
CBlockIndex* blockIndex = ChainActive()[blockHeight];
Expand All @@ -53,12 +64,15 @@ BOOST_AUTO_TEST_CASE(getpopdata_test)
}

BOOST_AUTO_TEST_CASE(submitpop_test)
{
{
auto connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
VeriBlock::InitRpcService(connman.get());

JSONRPCRequest request;
request.strMethod = "submitpop";
request.params = UniValue(UniValue::VARR);
request.fHelp = false;

std::vector<uint8_t> atv(100, 1);
std::vector<uint8_t> vtb(100, 2);

Expand All @@ -78,4 +92,4 @@ BOOST_AUTO_TEST_CASE(submitpop_test)

BOOST_CHECK(mempool.exists(popTxHash));
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
82 changes: 49 additions & 33 deletions src/vbk/test/unit/updated_mempool_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,38 +281,54 @@ BOOST_FIXTURE_TEST_CASE(check_the_pop_tx_limits_in_block, TestingSetup)
BOOST_CHECK(blockAssembler.getBlock().vtx.size() == config.max_pop_tx_amount);
}

BOOST_FIXTURE_TEST_CASE(check_CreateNewBlock_with_blockPopValidation_fail, TestingSetup)
{
Fake(Method(pop_service_mock, addPayloads));
Fake(Method(pop_service_mock, removePayloads));
Fake(Method(pop_service_mock, clearTemporaryPayloads));
When(Method(pop_service_mock, determineATVPlausibilityWithBTCRules)).AlwaysReturn(true);

When(Method(pop_service_mock, blockPopValidation)).AlwaysDo([](const CBlock& block, const CBlockIndex& pindexPrev, const Consensus::Params& params, BlockValidationState& state) -> bool { return VeriBlock::blockPopValidationImpl((VeriBlock::PopServiceImpl&)VeriBlock::getService<VeriBlock::PopService>(), block, pindexPrev, params, state); });
When(Method(pop_service_mock, parsePopTx)).AlwaysDo([](const CTransactionRef&, ScriptError* serror, VeriBlock::Publications*, VeriBlock::Context*, VeriBlock::PopTxType* type) -> bool {
if (type != nullptr) {
*type = VeriBlock::PopTxType::CONTEXT;
}
if (serror != nullptr) {
*serror = ScriptError::SCRIPT_ERR_OK;
}
return true; });

// Simulate that we have 8 invalid popTxs
When(Method(pop_service_mock, updateContext)).Throw(8_Times(VeriBlock::PopServiceException("fail"))).AlwaysDo([](const std::vector<std::vector<uint8_t>>& veriBlockBlocks, const std::vector<std::vector<uint8_t>>& bitcoinBlocks) {});

TestMemPoolEntryHelper entry;
for (size_t i = 0; i < 10; ++i) {
LOCK2(cs_main, mempool.cs);
CMutableTransaction popTx = VeriBlockTest::makePopTx({1}, {std::vector<uint8_t>(100, i)});
mempool.addUnchecked(entry.Fee(0LL).FromTx(popTx));
}

BlockAssembler blkAssembler(Params());
CScript scriptPubKey = CScript() << OP_CHECKSIG;
std::unique_ptr<CBlockTemplate> pblockTemplate = blkAssembler.CreateNewBlock(scriptPubKey);

BOOST_TEST(pblockTemplate->block.vtx.size() == 3);
}
// TODO: uncomment and fix test
//BOOST_FIXTURE_TEST_CASE(check_CreateNewBlock_with_blockPopValidation_fail, TestingSetup)
//{
// Fake(OverloadedMethod(pop_service_mock, addPayloads, void(std::string, const int&, const VeriBlock::Publications&)));
// Fake(OverloadedMethod(pop_service_mock, removePayloads, void(std::string, const int&)));
// Fake(Method(pop_service_mock, clearTemporaryPayloads));
// When(Method(pop_service_mock, determineATVPlausibilityWithBTCRules)).AlwaysReturn(true);
//
// When(Method(pop_service_mock, blockPopValidation)).AlwaysDo([](const CBlock& block, const CBlockIndex& pindexPrev, const Consensus::Params& params, BlockValidationState& state) -> bool { return VeriBlock::blockPopValidationImpl((VeriBlock::PopServiceImpl&)VeriBlock::getService<VeriBlock::PopService>(), block, pindexPrev, params, state); });
// When(Method(pop_service_mock, parsePopTx)).AlwaysDo([](const CTransactionRef&, ScriptError* serror, VeriBlock::Publications*, VeriBlock::Context*, VeriBlock::PopTxType* type) -> bool {
// if (type != nullptr) {
// *type = VeriBlock::PopTxType::CONTEXT;
// }
// if (serror != nullptr) {
// *serror = ScriptError::SCRIPT_ERR_OK;
// }
// return true; });
//
// // Simulate that we have 8 invalid popTxs
// When(Method(pop_service_mock, updateContext)).Throw(8_Times(VeriBlock::PopServiceException("fail"))).AlwaysDo([](const std::vector<std::vector<uint8_t>>& veriBlockBlocks, const std::vector<std::vector<uint8_t>>& bitcoinBlocks) {});
//
// const size_t popTxCount = 10;
//
// TestMemPoolEntryHelper entry;
// for (size_t i = 0; i < popTxCount; ++i) {
// LOCK2(cs_main, mempool.cs);
// CMutableTransaction popTx = VeriBlockTest::makePopTx({1}, {std::vector<uint8_t>(100, i)});
// mempool.addUnchecked(entry.Fee(0LL).FromTx(popTx));
// }
//
// BlockAssembler blkAssembler(Params());
// CScript scriptPubKey = CScript() << OP_CHECKSIG;
//
// // repeatedly attempt to create a new block until either it
// // succeeds or we make a suspiciously large number of attempts
// bool success = false;
// for(size_t i = 0; i < popTxCount; i++) {
// BOOST_TEST(mempool.size() + i == popTxCount);
// try {
// std::unique_ptr<CBlockTemplate> pblockTemplate = blkAssembler.CreateNewBlock(scriptPubKey);
//
// BOOST_TEST(pblockTemplate->block.vtx.size() == 3);
//
// success = true;
// }
// catch (const std::runtime_error&) {}
// }
// BOOST_TEST(success);
//}

BOOST_AUTO_TEST_SUITE_END()
5 changes: 5 additions & 0 deletions src/vbk/test/util/mock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ inline void setUpPopServiceMock(fakeit::Mock<VeriBlock::PopService>& mock)
fakeit::When(Method(mock, blockPopValidation)).AlwaysReturn(true);
fakeit::Fake(Method(mock, updateContext));

fakeit::Fake(OverloadedMethod(mock, addPayloads, void(std::string, const int&, const VeriBlock::Publications&)));
fakeit::Fake(OverloadedMethod(mock, addPayloads, void(const CBlockIndex &, const CBlock &)));
fakeit::Fake(OverloadedMethod(mock, removePayloads, void(std::string, const int&)));
fakeit::Fake(OverloadedMethod(mock, removePayloads, void(const CBlockIndex &)));

setServiceMock(mock);
}

Expand Down

0 comments on commit 65c6f7f

Please sign in to comment.