bitshares / bitshares/bitshares-core
Expired transactions with expiration time later than last block are possible to be included in a new block
- Dominant language
- C++
- Stars
- 1.2k
- Forks
- 660
- Avg merge
- 8h 17m
- Merged PRs (30d)
- 26
Description
The `expiration` field of transactions is checked in `_apply_transaction()` in `db_block.cpp` ([code](https://github.com/bitshares/bitshares-core/blob/bf4b80ece55f83524b111492480088dbb0ff9139/libraries/chain/db_block.cpp#L595-L599)):
```
fc::time_point_sec now = head_block_time();
FC_ASSERT( trx.expiration <= now + chain_parameters.maximum_time_until_expiration, "",
("trx.expiration",trx.expiration)("now",now)("max_til_exp",chain_parameters.maximum_time_until_expiration));
FC_ASSERT( now <= trx.expiration, "", ("now",now)("trx.exp",trx.expiration) );
```
`head_block_time()` is implemented in `db_getter.cpp` ([code](https://github.com/bitshares/bitshares-core/blob/bf4b80ece55f83524b111492480088dbb0ff9139/libraries/chain/db_getter.cpp#L60-L63)):
```
time_point_sec database::head_block_time()const
{
return get( dynamic_global_property_id_type() ).time;
}
```
The `time` field is updated in `update_global_dynamic_data()` in `db_update.cpp` ([code](https://github.com/bitshares/bitshares-core/blob/bf4b80ece55f83524b111492480088dbb0ff9139/libraries/chain/db_update.cpp#L81)):
```
void database::update_global_dynamic_data( const signed_block& b )
{
...
modify( _dgp, [&]( dynamic_global_property_object& dgp ){
...
dgp.time = b.timestamp;
...
```
But `_apply_transaction()` is called before `update_global_dynamic_data(next_block)` in `_apply_block()` ([code](https://github.com/bitshares/bitshares-core/blob/bf4b80ece55f83524b111492480088dbb0ff9139/libraries/chain/db_block.cpp#L504-L516)):
```
for( const auto& trx : next_block.transactions )
{
apply_transaction( trx, skip );
++_current_trx_in_block;
}
update_global_dynamic_data(next_block);
```
So theoretically if a transaction's `expiration` field is later than last block's timestamp, but earlier than the new block's timestamp, it can still be included in the new block and pass the check? Please let me know if I'm wrong.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by tracing _apply_block() and apply_transaction() in libraries/chain/db_block.cpp, then compare head_block_time() in db_getter.cpp with update_global_dynamic_data() in db_update.cpp. Confirm whether transaction validation uses the previous block timestamp and determine whether an expiration between the two timestamps can be accepted; done means the behavior is conclusively explained and any required correction is identified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- blockchain
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100