Skip to content

Commit 05bb716

Browse files
Added tests to verify if a block with a invalid transaction was accepted by a chain when the block was produced by a trusted producer. GH #5268
1 parent a972330 commit 05bb716

File tree

1 file changed

+113
-1
lines changed

1 file changed

+113
-1
lines changed

unittests/block_tests.cpp

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,119 @@ BOOST_AUTO_TEST_CASE(block_with_invalid_tx_test)
4747
[] (const fc::exception &e)->bool {
4848
return e.code() == account_name_exists_exception::code_value ;
4949
}) ;
50-
50+
51+
}
52+
53+
std::pair<signed_block_ptr, signed_block_ptr> corrupt_trx_in_block(validating_tester& main, account_name act_name) {
54+
// First we create a valid block with valid transaction
55+
main.create_account(act_name);
56+
signed_block_ptr b = main.produce_block_no_validation();
57+
58+
// Make a copy of the valid block and corrupt the transaction
59+
auto copy_b = std::make_shared<signed_block>(*b);
60+
auto signed_tx = copy_b->transactions.back().trx.get<packed_transaction>().get_signed_transaction();
61+
// Corrupt one signature
62+
signed_tx.signatures.clear();
63+
signed_tx.sign(main.get_private_key(act_name, "active"), main.control->get_chain_id());
64+
65+
// Replace the valid transaction with the invalid transaction
66+
auto invalid_packed_tx = packed_transaction(signed_tx);
67+
copy_b->transactions.back().trx = invalid_packed_tx;
68+
69+
// Re-calculate the transaction merkle
70+
vector<digest_type> trx_digests;
71+
const auto& trxs = copy_b->transactions;
72+
trx_digests.reserve( trxs.size() );
73+
for( const auto& a : trxs )
74+
trx_digests.emplace_back( a.digest() );
75+
copy_b->transaction_mroot = merkle( move(trx_digests) );
76+
77+
// Re-sign the block
78+
auto header_bmroot = digest_type::hash( std::make_pair( copy_b->digest(), main.control->head_block_state()->blockroot_merkle.get_root() ) );
79+
auto sig_digest = digest_type::hash( std::make_pair(header_bmroot, main.control->head_block_state()->pending_schedule_hash) );
80+
copy_b->producer_signature = main.get_private_key(b->producer, "active").sign(sig_digest);
81+
return std::pair<signed_block_ptr, signed_block_ptr>(b, copy_b);
82+
}
83+
84+
// verify that a block with a transaction with an incorrect signature, is blindly accepted from a trusted producer
85+
BOOST_AUTO_TEST_CASE(trusted_producer_test)
86+
{
87+
flat_set<account_name> trusted_producers = { N(defproducera), N(defproducerc) };
88+
validating_tester main(trusted_producers);
89+
// only using validating_tester to keep the 2 chains in sync, not to validate that the validating_node matches the main node,
90+
// since it won't be
91+
main.skip_validate = true;
92+
93+
// First we create a valid block with valid transaction
94+
std::set<account_name> producers = { N(defproducera), N(defproducerb), N(defproducerc), N(defproducerd) };
95+
for (auto prod : producers)
96+
main.create_account(prod);
97+
auto b = main.produce_block();
98+
99+
std::vector<account_name> schedule(producers.cbegin(), producers.cend());
100+
auto trace = main.set_producers(schedule);
101+
102+
while (b->producer != N(defproducera)) {
103+
b = main.produce_block();
104+
}
105+
106+
auto blocks = corrupt_trx_in_block(main, N(tstproducera));
107+
main.validate_push_block( blocks.second );
108+
}
109+
110+
// like trusted_producer_test, except verify that any entry in the trusted_producer list is accepted
111+
BOOST_AUTO_TEST_CASE(trusted_producer_verify_2nd_test)
112+
{
113+
flat_set<account_name> trusted_producers = { N(defproducera), N(defproducerc) };
114+
validating_tester main(trusted_producers);
115+
// only using validating_tester to keep the 2 chains in sync, not to validate that the validating_node matches the main node,
116+
// since it won't be
117+
main.skip_validate = true;
118+
119+
// First we create a valid block with valid transaction
120+
std::set<account_name> producers = { N(defproducera), N(defproducerb), N(defproducerc), N(defproducerd) };
121+
for (auto prod : producers)
122+
main.create_account(prod);
123+
auto b = main.produce_block();
124+
125+
std::vector<account_name> schedule(producers.cbegin(), producers.cend());
126+
auto trace = main.set_producers(schedule);
127+
128+
while (b->producer != N(defproducerc)) {
129+
b = main.produce_block();
130+
}
131+
132+
auto blocks = corrupt_trx_in_block(main, N(tstproducera));
133+
main.validate_push_block( blocks.second );
134+
}
135+
136+
// verify that a block with a transaction with an incorrect signature, is rejected if it is not from a trusted producer
137+
BOOST_AUTO_TEST_CASE(untrusted_producer_test)
138+
{
139+
flat_set<account_name> trusted_producers = { N(defproducera), N(defproducerc) };
140+
validating_tester main(trusted_producers);
141+
// only using validating_tester to keep the 2 chains in sync, not to validate that the validating_node matches the main node,
142+
// since it won't be
143+
main.skip_validate = true;
144+
145+
// First we create a valid block with valid transaction
146+
std::set<account_name> producers = { N(defproducera), N(defproducerb), N(defproducerc), N(defproducerd) };
147+
for (auto prod : producers)
148+
main.create_account(prod);
149+
auto b = main.produce_block();
150+
151+
std::vector<account_name> schedule(producers.cbegin(), producers.cend());
152+
auto trace = main.set_producers(schedule);
153+
154+
while (b->producer != N(defproducerb)) {
155+
b = main.produce_block();
156+
}
157+
158+
auto blocks = corrupt_trx_in_block(main, N(tstproducera));
159+
BOOST_REQUIRE_EXCEPTION(main.validate_push_block( blocks.second ), fc::exception ,
160+
[] (const fc::exception &e)->bool {
161+
return e.code() == unsatisfied_authorization::code_value ;
162+
}) ;
51163
}
52164

53165
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)