Skip to content

Commit

Permalink
Make reward amount check stricter
Browse files Browse the repository at this point in the history
Signed-off-by: Azat Nizametdinov <[email protected]>
  • Loading branch information
Nizametdinov committed May 13, 2019
1 parent 008056b commit 929bfe5
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 36 deletions.
8 changes: 4 additions & 4 deletions src/staking/block_reward_validator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class BlockRewardValidatorImpl : public BlockRewardValidator {
assert(MoneyRange(fees));

const CBlockIndex &prev_block = *index.pprev;
CAmount total_reward = fees + m_behavior->CalculateBlockReward(prev_block.nHeight);
CAmount total_reward = fees + m_behavior->CalculateBlockReward(index.nHeight);

std::size_t num_reward_outputs = 1;

Expand All @@ -40,8 +40,8 @@ class BlockRewardValidatorImpl : public BlockRewardValidator {
REJECT_INVALID, "bad-cb-amount");
}

// TODO UNIT-E: make the check stricter: if (coinbase_tx.GetValueOut() - input_amount < block_reward)
if (output_amount < input_amount) {
// TODO UNIT-E: make the check stricter: if (output_amount - input_amount < total_reward)
if (output_amount - input_amount < total_reward - fees) {
return state.DoS(100,
error("%s: coinbase pays too little (total output=%d total input=%d expected reward=%d )",
__func__, FormatMoney(output_amount), FormatMoney(input_amount),
Expand All @@ -68,4 +68,4 @@ std::unique_ptr<BlockRewardValidator> BlockRewardValidator::New(
Dependency<blockchain::Behavior> behavior) {
return MakeUnique<BlockRewardValidatorImpl>(behavior);
}
} // namespace staking
} // namespace staking
45 changes: 13 additions & 32 deletions src/test/staking/block_reward_validator_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace {
struct Fixture {

const CAmount total_reward = 10 * UNIT;
const CAmount immediate_reward = 1 * UNIT;

blockchain::Parameters parameters = [this]() {
blockchain::Parameters p = blockchain::Parameters::TestNet();
Expand Down Expand Up @@ -52,26 +53,6 @@ struct Fixture {
return tx;
}

CTransaction MakeCoinbaseTx(
CAmount block_reward,
const std::vector<std::pair<CScript, CAmount>> &finalization_rewards,
const std::vector<CAmount> &outputs) {
const CTxIn meta_input;
const CTxIn staking_input;

CMutableTransaction tx;
tx.SetType(TxType::COINBASE);
tx.vin = {meta_input, staking_input};
tx.vout.emplace_back(block_reward, CScript());
for (const auto &r : finalization_rewards) {
tx.vout.emplace_back(r.second, r.first);
}
for (const auto out : outputs) {
tx.vout.emplace_back(out, CScript());
}
return tx;
}

std::unique_ptr<staking::BlockRewardValidator> GetBlockRewardValidator() {
return staking::BlockRewardValidator::New(b.get());
}
Expand All @@ -86,7 +67,7 @@ BOOST_AUTO_TEST_CASE(valid_reward) {
const auto validator = f.GetBlockRewardValidator();

const CAmount input_amount = 10 * UNIT;
const CAmount fees = 1 * UNIT;
const CAmount fees = UNIT / 2;

auto test_valid_outputs = [&](const std::vector<CAmount> outputs) {
CTransaction tx = f.MakeCoinbaseTx(outputs);
Expand All @@ -96,18 +77,18 @@ BOOST_AUTO_TEST_CASE(valid_reward) {
BOOST_CHECK(result);
BOOST_CHECK(validation_state.IsValid());
};
test_valid_outputs({1 * UNIT + fees, input_amount});
test_valid_outputs({1 * UNIT + fees, input_amount / 2, input_amount / 2});
test_valid_outputs({1 * UNIT + fees + input_amount});
test_valid_outputs({input_amount});
test_valid_outputs({f.immediate_reward + fees, input_amount});
test_valid_outputs({f.immediate_reward + fees, input_amount / 2, input_amount / 2});
test_valid_outputs({f.immediate_reward + fees + input_amount});
test_valid_outputs({f.immediate_reward + input_amount});
}

BOOST_AUTO_TEST_CASE(total_output_is_too_large) {
Fixture f;
const auto validator = f.GetBlockRewardValidator();

const CAmount input_amount = 11 * UNIT;
const CAmount fees = 1 * UNIT;
const CAmount fees = UNIT / 2;
auto test_invalid_outputs = [&](const std::vector<CAmount> outputs) {
CTransaction tx = f.MakeCoinbaseTx(outputs);
CValidationState validation_state;
Expand All @@ -118,17 +99,17 @@ BOOST_AUTO_TEST_CASE(total_output_is_too_large) {
BOOST_CHECK_EQUAL(validation_state.GetRejectCode(), REJECT_INVALID);
BOOST_CHECK_EQUAL(validation_state.GetRejectReason(), "bad-cb-amount");
};
test_invalid_outputs({1 * UNIT + fees + 1, input_amount});
test_invalid_outputs({1 * UNIT + fees, input_amount + 1});
test_invalid_outputs({f.immediate_reward + fees + 1, input_amount});
test_invalid_outputs({f.immediate_reward + fees, input_amount + 1});
}

BOOST_AUTO_TEST_CASE(total_output_is_too_small) {
Fixture f;
const auto validator = f.GetBlockRewardValidator();

const CAmount input_amount = 11 * UNIT;
const CAmount fees = 1 * UNIT;
CTransaction tx = f.MakeCoinbaseTx({0, input_amount - 1});
const CAmount fees = UNIT / 2;
CTransaction tx = f.MakeCoinbaseTx({0, input_amount});
CValidationState validation_state;

const bool result = validator->CheckBlockRewards(tx, validation_state, f.block, input_amount, fees);
Expand All @@ -143,8 +124,8 @@ BOOST_AUTO_TEST_CASE(non_reward_output_is_too_large) {
const auto validator = f.GetBlockRewardValidator();

const CAmount input_amount = 15 * UNIT;
const CAmount fees = 1 * UNIT;
CTransaction tx = f.MakeCoinbaseTx({1 * UNIT, input_amount + fees});
const CAmount fees = UNIT / 2;
CTransaction tx = f.MakeCoinbaseTx({f.immediate_reward, input_amount + fees});
CValidationState validation_state;

const bool result = validator->CheckBlockRewards(tx, validation_state, f.block, input_amount, fees);
Expand Down

0 comments on commit 929bfe5

Please sign in to comment.