Skip to content

Commit

Permalink
Merge pull request #4 from VeriBlock/feature/btc-151
Browse files Browse the repository at this point in the history
add halving into the pop rewards
  • Loading branch information
Warchant committed Jan 9, 2020
2 parents b6f5a27 + 8503011 commit fd0bd19
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\test\setup_common.cpp" />
<ClCompile Include="..\..\src\vbk\test\integration\dummy.cpp" />
<ClCompile Include="..\..\src\test\util\setup_common.cpp" />
<ClCompile Include="..\..\src\vbk\test\integration\main.cpp" />
<ClCompile Include="..\..\src\vbk\test\integration\utils.cpp" />
<ClCompile Include="..\..\src\vbk\test\integration\grpc_integration_service.cpp" />
Expand Down
2 changes: 1 addition & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;

VeriBlock::getService<VeriBlock::UtilService>().addPopPayoutsIntoCoinbaseTx(coinbaseTx, *pindexPrev);
VeriBlock::getService<VeriBlock::UtilService>().addPopPayoutsIntoCoinbaseTx(coinbaseTx, *pindexPrev, chainparams.GetConsensus());

pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
result.pushKV("pop_witness_commitment", HexStr(popCoinbaseCommitment.scriptPubKey.begin(), popCoinbaseCommitment.scriptPubKey.end()));

UniValue popRewardsArray(UniValue::VARR);
VeriBlock::PoPRewards popRewards = VeriBlock::getService<VeriBlock::UtilService>().getPopRewards(*pindexPrev);
VeriBlock::PoPRewards popRewards = VeriBlock::getService<VeriBlock::UtilService>().getPopRewards(*pindexPrev, Params().GetConsensus());
for (const auto& itr : popRewards) {
UniValue popRewardValue(UniValue::VOBJ);
popRewardValue.pushKV("payout_info", HexStr(itr.first.begin(), itr.first.end()));
Expand Down
4 changes: 2 additions & 2 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2179,14 +2179,14 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,

auto& utilService = VeriBlock::getService<VeriBlock::UtilService>();
CAmount PoPrewards = 0;
for (const auto& it : utilService.getPopRewards(*pindex->pprev)) {
for (const auto& it : utilService.getPopRewards(*pindex->pprev, chainparams.GetConsensus())) {
PoPrewards += it.second;
}
assert(PoPrewards >= 0);

CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()) + PoPrewards;
assert(pindex->pprev && "previous block ptr is nullptr");
if (!VeriBlock::getService<VeriBlock::UtilService>().checkCoinbaseTxWithPopRewards(*block.vtx[0], blockReward, *pindex->pprev, state)) {
if (!VeriBlock::getService<VeriBlock::UtilService>().checkCoinbaseTxWithPopRewards(*block.vtx[0], blockReward, *pindex->pprev, chainparams.GetConsensus(), state)) {
return false;
}

Expand Down
1 change: 1 addition & 0 deletions src/vbk/entity/publications.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef INTEGRATION_REFERENCE_BTC_PUBLICATIONS_HPP
#define INTEGRATION_REFERENCE_BTC_PUBLICATIONS_HPP

#include <stdint.h>
#include <vector>

namespace VeriBlock {
Expand Down
2 changes: 1 addition & 1 deletion src/vbk/pop_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct PopService {

virtual int compareTwoBranches(const CBlockIndex* commonKeystone, const CBlockIndex* leftForkTip, const CBlockIndex* rightForkTip) = 0;

virtual void rewardsCalculateOutputs(const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex& difficulty_start_interval, const CBlockIndex& difficulty_end_interval, std::map<CScript, int64_t>& outputs) = 0;
virtual void rewardsCalculateOutputs(const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex* difficulty_start_interval, const CBlockIndex* difficulty_end_interval, std::map<CScript, int64_t>& outputs) = 0;

virtual bool blockPopValidation(const CBlock& block, const CBlockIndex& pindexPrev, const Consensus::Params& params, BlockValidationState& state) = 0;

Expand Down
8 changes: 5 additions & 3 deletions src/vbk/pop_service/pop_service_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ int PopServiceImpl::compareTwoBranches(const CBlockIndex* commonKeystone, const
}

// Pop rewards
void PopServiceImpl::rewardsCalculateOutputs(const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex& difficulty_start_interval, const CBlockIndex& difficulty_end_interval, std::map<CScript, int64_t>& outputs)
void PopServiceImpl::rewardsCalculateOutputs(const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex* difficulty_start_interval, const CBlockIndex* difficulty_end_interval, std::map<CScript, int64_t>& outputs)
{
RewardsCalculateRequest request;
RewardsCalculateReply reply;
Expand All @@ -339,9 +339,11 @@ void PopServiceImpl::rewardsCalculateOutputs(const int& blockHeight, const CBloc
workingBlock = workingBlock->pprev;
}

workingBlock = &difficulty_end_interval;
workingBlock = difficulty_end_interval;

while (workingBlock != difficulty_start_interval.pprev) // including the start_interval block
CBlockIndex* pprev_difficulty_start_interval = difficulty_start_interval != nullptr ? difficulty_start_interval->pprev : nullptr;

while (workingBlock != pprev_difficulty_start_interval) // including the start_interval block
{
AltChainBlock* b = request.add_difficultyblocks();
::BlockToProtoAltChainBlock(*workingBlock, *b);
Expand Down
4 changes: 2 additions & 2 deletions src/vbk/pop_service/pop_service_impl.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#ifndef BITCOIN_SRC_VBK_POP_SERVICE_POP_SERVICE_IMPL_HPP
#define BITCOIN_SRC_VBK_POP_SERVICE_POP_SERVICE_IMPL_HPP

#include <vbk/entity/publications.hpp>
#include <vbk/pop_service.hpp>
#include <vbk/pop_service/pop_service_exception.hpp>
#include <vbk/entity/publications.hpp>

#include <memory>
#include <vector>
Expand Down Expand Up @@ -36,7 +36,7 @@ class PopServiceImpl : public PopService

int compareTwoBranches(const CBlockIndex* commonKeystone, const CBlockIndex* leftForkTip, const CBlockIndex* rightForkTip) override;

void rewardsCalculateOutputs(const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex& difficulty_start_interval, const CBlockIndex& difficulty_end_interval, std::map<CScript, int64_t>& outputs) override;
void rewardsCalculateOutputs(const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex* difficulty_start_interval, const CBlockIndex* difficulty_end_interval, std::map<CScript, int64_t>& outputs) override;

bool blockPopValidation(const CBlock& block, const CBlockIndex& pindexPrev, const Consensus::Params& params, BlockValidationState& state) override;

Expand Down
8 changes: 4 additions & 4 deletions src/vbk/test/integration/test_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ IntegrationTestFixture::IntegrationTestFixture() : TestChain100Setup()
});
When(Method(util_service_mock, validatePopTx)).AlwaysReturn(true);
When(Method(util_service_mock, checkCoinbaseTxWithPopRewards)).AlwaysReturn(true);
When(Method(util_service_mock, getPopRewards)).AlwaysDo([&](const CBlockIndex& pindexPrev) -> VeriBlock::PoPRewards {
return util_service_impl.getPopRewards(pindexPrev);
When(Method(util_service_mock, getPopRewards)).AlwaysDo([&](const CBlockIndex& pindexPrev, const Consensus::Params& consensusParams) -> VeriBlock::PoPRewards {
return util_service_impl.getPopRewards(pindexPrev, consensusParams);
});
When(Method(util_service_mock, addPopPayoutsIntoCoinbaseTx)).AlwaysDo([&](CMutableTransaction& coinbaseTx, const CBlockIndex& pindexPrev) -> void {
return util_service_impl.addPopPayoutsIntoCoinbaseTx(coinbaseTx, pindexPrev);
When(Method(util_service_mock, addPopPayoutsIntoCoinbaseTx)).AlwaysDo([&](CMutableTransaction& coinbaseTx, const CBlockIndex& pindexPrev, const Consensus::Params& consensusParams) -> void {
return util_service_impl.addPopPayoutsIntoCoinbaseTx(coinbaseTx, pindexPrev, consensusParams);
});

When(Method(util_service_mock, makeTopLevelRoot)).AlwaysDo([&](int height, const VeriBlock::KeystoneArray& keystones, const uint256& txRoot) -> uint256 {
Expand Down
127 changes: 81 additions & 46 deletions src/vbk/test/unit/pop_reward_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,33 @@
#include <validation.h>
#include <wallet/wallet.h>

#include <vbk/config.hpp>
#include <vbk/pop_service/pop_service_impl.hpp>
#include <vbk/service_locator.hpp>
#include <vbk/test/util/mock.hpp>

#include <fakeit.hpp>
using namespace fakeit;

struct PopRewardsTestFixture : public TestChain100Setup, VeriBlockTest::ServicesFixture {
//VeriBlockTest::ServicesFixture service_fixture;

PopRewardsTestFixture()
{
When(Method(util_service_mock, getPopRewards)).AlwaysDo([&](const CBlockIndex& pindexPrev, const Consensus::Params& consensusParams) {
return util_service_impl.getPopRewards(pindexPrev, consensusParams);
});

When(Method(util_service_mock, addPopPayoutsIntoCoinbaseTx)).AlwaysDo([&](CMutableTransaction& coinbaseTx, const CBlockIndex& pindexPrev, const Consensus::Params& consensusParams) {
util_service_impl.addPopPayoutsIntoCoinbaseTx(coinbaseTx, pindexPrev, consensusParams);
});

When(Method(util_service_mock, checkCoinbaseTxWithPopRewards)).AlwaysDo([&](const CTransaction& tx, const CAmount& PoWBlockReward, const CBlockIndex& pindexPrev, const Consensus::Params& consensusParams, BlockValidationState& state) -> bool {
return util_service_impl.checkCoinbaseTxWithPopRewards(tx, PoWBlockReward, pindexPrev, consensusParams, state);
});
}
};

BOOST_AUTO_TEST_SUITE(pop_reward_tests)

static VeriBlock::PoPRewards getRewards()
Expand All @@ -30,80 +51,94 @@ static VeriBlock::PoPRewards getRewards()
return rewards;
}


BOOST_FIXTURE_TEST_CASE(addPopPayoutsIntoCoinbaseTx_test, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(addPopPayoutsIntoCoinbaseTx_test, PopRewardsTestFixture)
{
VeriBlockTest::ServicesFixture serviceFixture;

VeriBlock::PoPRewards rewards = getRewards();
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;

When(Method(serviceFixture.util_service_mock, getPopRewards)).AlwaysDo([&rewards](const CBlockIndex& pindexPrev) -> VeriBlock::PoPRewards {
return rewards;
});
while (ChainActive().Height() < VeriBlock::getService<VeriBlock::Config>().POP_REWARD_PAYMENT_DELAY) {
CreateAndProcessBlock({}, scriptPubKey);
}

When(Method(serviceFixture.util_service_mock, addPopPayoutsIntoCoinbaseTx)).AlwaysDo([&serviceFixture](CMutableTransaction& coinbaseTx, const CBlockIndex& pindexPrev) {
serviceFixture.util_service_impl.addPopPayoutsIntoCoinbaseTx(coinbaseTx, pindexPrev);
VeriBlock::PoPRewards rewards = getRewards();
When(Method(pop_service_mock, rewardsCalculateOutputs)).AlwaysDo([&rewards](const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex* difficulty_start_interval, const CBlockIndex* difficulty_end_interval, std::map<CScript, int64_t>& outputs) {
outputs = rewards;
});

CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
CBlock block = CreateAndProcessBlock({}, scriptPubKey);

CAmount PoWReward = GetBlockSubsidy(ChainActive().Height(), Params().GetConsensus());

BOOST_CHECK((PoWReward + 105) == block.vtx[0]->GetValueOut());

for (auto i = 0u; i < rewards.size(); ++i) {
CScript payoutInfo = block.vtx[0]->vout[i + 1].scriptPubKey;
BOOST_CHECK(block.vtx[0]->vout[i + 1].nValue == rewards[payoutInfo]);
int n = 0;
for (const auto& out : block.vtx[0]->vout) {
if (rewards.find(out.scriptPubKey) != rewards.end()) {
n++;
}
}
// have found 4 pop rewards
BOOST_CHECK(n == 4);
}

BOOST_FIXTURE_TEST_CASE(checkCoinbaseTxWithPopRewards, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(checkCoinbaseTxWithPopRewards, PopRewardsTestFixture)
{
VeriBlockTest::ServicesFixture serviceFixture;

VeriBlock::PoPRewards rewards = getRewards();

When(Method(serviceFixture.util_service_mock, getPopRewards)).AlwaysDo([rewards](const CBlockIndex& pindexPrev) -> VeriBlock::PoPRewards {
return rewards;
});
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;

When(Method(serviceFixture.util_service_mock, addPopPayoutsIntoCoinbaseTx)).AlwaysDo([&serviceFixture](CMutableTransaction& coinbaseTx, const CBlockIndex& pindexPrev) {
serviceFixture.util_service_impl.addPopPayoutsIntoCoinbaseTx(coinbaseTx, pindexPrev);
});
while (ChainActive().Height() < VeriBlock::getService<VeriBlock::Config>().POP_REWARD_PAYMENT_DELAY) {
CreateAndProcessBlock({}, scriptPubKey);
}

When(Method(serviceFixture.util_service_mock, checkCoinbaseTxWithPopRewards)).AlwaysDo([&serviceFixture](const CTransaction& tx, const CAmount& PoWBlockReward, const CBlockIndex& pindexPrev, BlockValidationState& state) -> bool {
return serviceFixture.util_service_impl.checkCoinbaseTxWithPopRewards(tx, PoWBlockReward, pindexPrev, state);
VeriBlock::PoPRewards rewards = getRewards();
When(Method(pop_service_mock, rewardsCalculateOutputs)).AlwaysDo([&rewards](const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex* difficulty_start_interval, const CBlockIndex* difficulty_end_interval, std::map<CScript, int64_t>& outputs) {
outputs = rewards;
});

CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
CBlock block = CreateAndProcessBlock({}, scriptPubKey);

BOOST_CHECK(block.GetHash() == ChainActive().Tip()->GetBlockHash()); // means that pop rewards are valid
Verify_Method(Method(serviceFixture.util_service_mock, checkCoinbaseTxWithPopRewards)).AtLeastOnce();
Verify_Method(Method(util_service_mock, checkCoinbaseTxWithPopRewards)).AtLeastOnce();

When(Method(serviceFixture.util_service_mock, checkCoinbaseTxWithPopRewards)).AlwaysReturn(false);
When(Method(util_service_mock, checkCoinbaseTxWithPopRewards)).AlwaysReturn(false);

BOOST_CHECK_THROW(CreateAndProcessBlock({}, scriptPubKey), std::runtime_error);

Verify_Method(Method(serviceFixture.util_service_mock, checkCoinbaseTxWithPopRewards)).AtLeastOnce();
Verify_Method(Method(util_service_mock, checkCoinbaseTxWithPopRewards)).AtLeastOnce();
}

BOOST_FIXTURE_TEST_CASE(check_wallet_balance_with_pop_reward, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(pop_reward_halving_test, PopRewardsTestFixture)
{
VeriBlockTest::ServicesFixture serviceFixture;

CAmount PoPReward = 56;
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;

while (ChainActive().Height() < Params().GetConsensus().nSubsidyHalvingInterval || ChainActive().Height() < VeriBlock::getService<VeriBlock::Config>().POP_REWARD_PAYMENT_DELAY) {
CreateAndProcessBlock({}, scriptPubKey);
}

VeriBlock::PoPRewards rewards;
rewards[scriptPubKey] = PoPReward;
CScript pop_payout = CScript() << std::vector<uint8_t>(5, 1);
rewards[pop_payout] = 50;

When(Method(serviceFixture.util_service_mock, getPopRewards)).AlwaysDo([rewards](const CBlockIndex& pindexPrev) -> VeriBlock::PoPRewards {
return rewards;
When(Method(pop_service_mock, rewardsCalculateOutputs)).AlwaysDo([&rewards](const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex* difficulty_start_interval, const CBlockIndex* difficulty_end_interval, std::map<CScript, int64_t>& outputs) {
outputs = rewards;
});

When(Method(serviceFixture.util_service_mock, addPopPayoutsIntoCoinbaseTx)).AlwaysDo([&serviceFixture](CMutableTransaction& coinbaseTx, const CBlockIndex& pindexPrev) {
serviceFixture.util_service_impl.addPopPayoutsIntoCoinbaseTx(coinbaseTx, pindexPrev);
CBlock block = CreateAndProcessBlock({}, scriptPubKey);

for (const auto& out : block.vtx[0]->vout) {
if (out.scriptPubKey == pop_payout) {
// 3 times halving (50 / 8)
BOOST_CHECK(6 == out.nValue);
}
}
}

BOOST_FIXTURE_TEST_CASE(check_wallet_balance_with_pop_reward, PopRewardsTestFixture)
{
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
VeriBlock::PoPRewards rewards;
rewards[scriptPubKey] = 56;

while (ChainActive().Height() < VeriBlock::getService<VeriBlock::Config>().POP_REWARD_PAYMENT_DELAY) {
CreateAndProcessBlock({}, scriptPubKey);
}

When(Method(pop_service_mock, rewardsCalculateOutputs)).AlwaysDo([&rewards](const int& blockHeight, const CBlockIndex& endorsedBlock, const CBlockIndex& contaningBlocksTip, const CBlockIndex* difficulty_start_interval, const CBlockIndex* difficulty_end_interval, std::map<CScript, int64_t>& outputs) {
outputs = rewards;
});

auto block = CreateAndProcessBlock({}, scriptPubKey);
Expand Down Expand Up @@ -135,8 +170,8 @@ BOOST_FIXTURE_TEST_CASE(check_wallet_balance_with_pop_reward, TestChain100Setup)
BOOST_CHECK(result.last_failed_block.IsNull());
BOOST_CHECK_EQUAL(result.last_scanned_block, tip->GetBlockHash());
BOOST_CHECK_EQUAL(*result.last_scanned_height, tip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, PoWReward + PoPReward);
// 3 times halving (56 / 8)
BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, PoWReward + 7);
}
}

BOOST_AUTO_TEST_SUITE_END()
12 changes: 7 additions & 5 deletions src/vbk/util_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

#include <array>

#include "vbk/entity/context_info_container.hpp"
#include "vbk/entity/publications.hpp"
#include <vbk/entity/context_info_container.hpp>
#include <vbk/entity/publications.hpp>

#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/script_error.h>
#include <consensus/params.h>

class CBlockIndex;
class TxValidationState;
Expand All @@ -32,9 +34,9 @@ struct UtilService {
virtual int compareForks(const CBlockIndex& left, const CBlockIndex& right) = 0;

// Pop rewards methods
virtual PoPRewards getPopRewards(const CBlockIndex& pindexPrev) = 0;
virtual void addPopPayoutsIntoCoinbaseTx(CMutableTransaction& coinbaseTx, const CBlockIndex& pindexPrev) = 0;
virtual bool checkCoinbaseTxWithPopRewards(const CTransaction& tx, const CAmount& PoWBlockReward, const CBlockIndex& pindexPrev, BlockValidationState& state) = 0;
virtual PoPRewards getPopRewards(const CBlockIndex& pindexPrev, const Consensus::Params& consensusParams) = 0;
virtual void addPopPayoutsIntoCoinbaseTx(CMutableTransaction& coinbaseTx, const CBlockIndex& pindexPrev, const Consensus::Params& consensusParams) = 0;
virtual bool checkCoinbaseTxWithPopRewards(const CTransaction& tx, const CAmount& PoWBlockReward, const CBlockIndex& pindexPrev, const Consensus::Params& consensusParams, BlockValidationState& state) = 0;

virtual bool validatePopTx(const CTransaction& tx, TxValidationState& state) = 0;

Expand Down
Loading

0 comments on commit fd0bd19

Please sign in to comment.