Skip to content

Commit bb21c6e

Browse files
authored
Fix ticket expiration (#603)
* Fix precommit check Signed-off-by: ortyomka <[email protected]> * Fix states Signed-off-by: ortyomka <[email protected]>
1 parent 7777777 commit bb21c6e

File tree

4 files changed

+112
-74
lines changed

4 files changed

+112
-74
lines changed

core/miner/impl/miner_impl.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ namespace fc::miner {
102102
scheduler,
103103
SelectAddress,
104104
fee_config);
105+
105106
OUTCOME_TRY(sealing,
106107
SealingImpl::newSealing(api,
107108
events,

core/miner/storage_fsm/impl/checks.cpp

+14-9
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace fc::mining::checks {
3333
using vm::actor::MethodParams;
3434
using vm::actor::builtin::states::MinerActorStatePtr;
3535
using vm::actor::builtin::types::miner::kChainFinality;
36+
using vm::actor::builtin::types::miner::kMaxPreCommitRandomnessLookback;
3637
using vm::actor::builtin::types::miner::kMaxProveCommitDuration;
3738
using vm::actor::builtin::types::miner::kPreCommitChallengeDelay;
3839
using vm::actor::builtin::types::miner::maxSealDuration;
@@ -78,10 +79,13 @@ namespace fc::mining::checks {
7879
continue;
7980
}
8081

81-
OUTCOME_TRY(proposal,
82-
api->StateMarketStorageDeal(piece.deal_info->deal_id,
83-
chain_head->key));
82+
const auto maybe_proposal = api->StateMarketStorageDeal(
83+
piece.deal_info->deal_id, chain_head->key);
84+
if (maybe_proposal.has_error()) {
85+
return ChecksError::kInvalidDeal;
86+
}
8487

88+
const auto &proposal{maybe_proposal.value()};
8589
if (miner_address != proposal.proposal.provider) {
8690
return ChecksError::kInvalidDeal;
8791
}
@@ -192,15 +196,10 @@ namespace fc::mining::checks {
192196
return ChecksError::kBadCommD;
193197
}
194198

195-
OUTCOME_TRY(network, api->StateNetworkVersion(tipset_key));
196-
OUTCOME_TRY(seal_duration, getMaxProveCommitDuration(network, sector_info));
197-
if (height - (sector_info->ticket_epoch + kChainFinality) > seal_duration) {
198-
return ChecksError::kExpiredTicket;
199-
}
200-
201199
OUTCOME_TRY(state_sector_precommit_info,
202200
getStateSectorPreCommitInfo(
203201
miner_address, sector_info, tipset_key, api));
202+
204203
if (state_sector_precommit_info.has_value()) {
205204
if (state_sector_precommit_info->info.seal_epoch
206205
!= sector_info->ticket_epoch) {
@@ -209,6 +208,12 @@ namespace fc::mining::checks {
209208
return ChecksError::kPrecommitOnChain;
210209
}
211210

211+
const ChainEpoch ticket_earliest = height - kMaxPreCommitRandomnessLookback;
212+
213+
if (sector_info->ticket_epoch < ticket_earliest) {
214+
return ChecksError::kExpiredTicket;
215+
}
216+
212217
return outcome::success();
213218
}
214219

core/miner/storage_fsm/impl/sealing_impl.cpp

+21-20
Original file line numberDiff line numberDiff line change
@@ -251,13 +251,13 @@ namespace fc::mining {
251251
auto sector_ref = minerSector(seal_proof_type, piece_location.sector);
252252

253253
if (sector_and_padding.padding.size != 0) {
254-
OUTCOME_TRY(sealer_->addPieceSync(
255-
sector_ref,
256-
VectorCoW(gsl::span<const UnpaddedPieceSize>(
257-
unsealed_sector.piece_sizes)),
258-
sector_and_padding.padding.size.unpadded(),
259-
PieceData::makeNull(),
260-
kDealSectorPriority));
254+
OUTCOME_TRY(
255+
sealer_->addPieceSync(sector_ref,
256+
VectorCoW(gsl::span<const UnpaddedPieceSize>(
257+
unsealed_sector.piece_sizes)),
258+
sector_and_padding.padding.size.unpadded(),
259+
PieceData::makeNull(),
260+
kDealSectorPriority));
261261

262262
unsealed_sector.stored += sector_and_padding.padding.size;
263263

@@ -282,14 +282,14 @@ namespace fc::mining {
282282
piece_location.offset = unsealed_sector.stored;
283283

284284
logger_->info("Add piece to sector {}", piece_location.sector);
285-
OUTCOME_TRY(piece_info,
286-
sealer_->addPieceSync(sector_ref,
287-
VectorCoW(
288-
gsl::span<const UnpaddedPieceSize>(
289-
unsealed_sector.piece_sizes)),
290-
size,
291-
std::move(piece_data),
292-
kDealSectorPriority));
285+
OUTCOME_TRY(
286+
piece_info,
287+
sealer_->addPieceSync(sector_ref,
288+
VectorCoW(gsl::span<const UnpaddedPieceSize>(
289+
unsealed_sector.piece_sizes)),
290+
size,
291+
std::move(piece_data),
292+
kDealSectorPriority));
293293

294294
context->pieces.push_back(Piece{
295295
.piece = piece_info,
@@ -623,14 +623,15 @@ namespace fc::mining {
623623
.to(SealingState::kPreCommit2)
624624
.action(CALLBACK_ACTION),
625625
SealingTransition(SealingEvent::kSectorSealPreCommit1Failed)
626-
.fromMany(SealingState::kPreCommit1, SealingState::kPreCommitting)
626+
.fromMany(SealingState::kPreCommit1,
627+
SealingState::kPreCommitting,
628+
SealingState::kPreCommitFail,
629+
SealingState::kCommitFail,
630+
SealingState::kComputeProofFail,
631+
SealingState::kSubmitPreCommitBatch)
627632
.to(SealingState::kSealPreCommit1Fail)
628633
.action(
629634
[](auto info, auto event, auto context, auto from, auto to) {
630-
if (from == SealingState::kCommitting) {
631-
return;
632-
}
633-
634635
info->invalid_proofs = 0;
635636
info->precommit2_fails = 0;
636637
}),

test/core/miner/checks_test.cpp

+76-45
Original file line numberDiff line numberDiff line change
@@ -413,16 +413,18 @@ namespace fc::mining::checks {
413413
}
414414

415415
/**
416-
* @given info, valid pieces, expired ticket
416+
* @given info, valid pieces, ticket, precommit on chain
417417
* @when try to check precommit
418-
* @then ChecksError::kExpiredTicket occurs
418+
* @then ChecksError::kPrecommitOnChain occurs
419419
*/
420-
TEST_F(CheckPrecommit, ExpiredTicket) {
420+
TEST_F(CheckPrecommit, PrecommitOnChain) {
421421
std::shared_ptr<SectorInfo> info = std::make_shared<SectorInfo>();
422422
api::DealId deal_id = 1;
423423

424+
SectorNumber sector = 1;
424425
PieceInfo piece{.size = PaddedPieceSize(2048), .cid = "010001020001"_cid};
425426
info->comm_d = "010001020001"_cid;
427+
info->sector_number = sector;
426428
info->pieces = {
427429
Piece{
428430
.piece = piece,
@@ -441,21 +443,28 @@ namespace fc::mining::checks {
441443
},
442444
};
443445

444-
MOCK_API(api_, ChainHead);
445446
TipsetKey head_key;
446-
auto head_tipset =
447-
std::make_shared<Tipset>(head_key, std::vector<api::BlockHeader>());
448-
EXPECT_CALL(mock_ChainHead, Call())
449-
.WillOnce(testing::Return(outcome::success(head_tipset)));
447+
api_->ChainHead = [&head_key]() -> outcome::result<TipsetCPtr> {
448+
auto tip =
449+
std::make_shared<Tipset>(head_key, std::vector<api::BlockHeader>());
450+
return tip;
451+
};
450452

451-
MOCK_API(api_, StateMarketStorageDeal);
452-
api::StorageDeal deal;
453-
deal.proposal.provider = Address::makeFromId(miner_id_);
454-
deal.proposal.piece_cid = piece.cid;
455-
deal.proposal.piece_size = piece.size;
456-
deal.proposal.start_epoch = 1;
457-
EXPECT_CALL(mock_StateMarketStorageDeal, Call(deal_id, head_key))
458-
.WillOnce(testing::Return(outcome::success(deal)));
453+
api_->StateMarketStorageDeal =
454+
[&piece, id{miner_id_}, deal_id, &head_key](
455+
api::DealId did,
456+
const TipsetKey &key) -> outcome::result<api::StorageDeal> {
457+
if (did == deal_id and key == head_key) {
458+
api::StorageDeal res;
459+
res.proposal.provider = Address::makeFromId(id);
460+
res.proposal.piece_cid = piece.cid;
461+
res.proposal.piece_size = piece.size;
462+
res.proposal.start_epoch = 1;
463+
return res;
464+
}
465+
466+
return ERROR_TEXT("ERROR");
467+
};
459468

460469
TipsetKey precommit_key{{CbCid::hash("01"_unhex),
461470
CbCid::hash("02"_unhex),
@@ -468,23 +477,50 @@ namespace fc::mining::checks {
468477

469478
MOCK_API(api_, StateNetworkVersion);
470479
EXPECT_CALL(mock_StateNetworkVersion, Call(precommit_key))
471-
.WillOnce(testing::Return(outcome::success(version_)));
472-
EXPECT_OUTCOME_TRUE(duration,
473-
checks::getMaxProveCommitDuration(version_, info));
474-
ChainEpoch height = duration
475-
+ vm::actor::builtin::types::miner::kChainFinality
476-
+ info->ticket_epoch + 1;
480+
.WillRepeatedly(testing::Return(outcome::success(version_)));
481+
482+
ChainEpoch height;
483+
484+
auto actor_key{"010001020003"_cid};
485+
SectorPreCommitOnChainInfo some_info;
486+
some_info.info.sealed_cid = "010001020006"_cid;
487+
EXPECT_OUTCOME_TRUE_1(
488+
actor_state_->precommitted_sectors.set(sector, some_info));
489+
EXPECT_OUTCOME_TRUE(cid_root,
490+
actor_state_->precommitted_sectors.hamt.flush());
491+
492+
api_->ChainReadObj = [&](CID key) -> outcome::result<Bytes> {
493+
if (key == actor_key) {
494+
return codec::cbor::encode(actor_state_);
495+
}
496+
if (key == cid_root) {
497+
EXPECT_OUTCOME_TRUE(root,
498+
getCbor<storage::hamt::Node>(ipld_, cid_root));
499+
return codec::cbor::encode(root);
500+
}
501+
if (key == actor_state_->allocated_sectors) {
502+
return codec::cbor::encode(primitives::RleBitset());
503+
}
504+
return ERROR_TEXT("ERROR");
505+
};
506+
507+
Actor actor;
508+
actor.code = vm::actor::builtin::v0::kStorageMinerCodeId;
509+
actor.head = actor_key;
510+
api_->StateGetActor = [&](const Address &addr, const TipsetKey &tipset_key)
511+
-> outcome::result<Actor> { return actor; };
512+
477513
EXPECT_OUTCOME_ERROR(
478-
ChecksError::kExpiredTicket,
514+
ChecksError::kPrecommitOnChain,
479515
checkPrecommit(miner_addr_, info, precommit_key, height, api_));
480516
}
481517

482518
/**
483519
* @given info, valid pieces, ticket, precommit on chain
484-
* @when try to check precommit
485-
* @then ChecksError::kPrecommitOnChain occurs
520+
* @when try to check precommit, but ticket with another epoch
521+
* @then ChecksError::kBadTicketEpoch occurs
486522
*/
487-
TEST_F(CheckPrecommit, PrecommitOnChain) {
523+
TEST_F(CheckPrecommit, BadTicketEpoch) {
488524
std::shared_ptr<SectorInfo> info = std::make_shared<SectorInfo>();
489525
api::DealId deal_id = 1;
490526

@@ -544,17 +580,15 @@ namespace fc::mining::checks {
544580

545581
MOCK_API(api_, StateNetworkVersion);
546582
EXPECT_CALL(mock_StateNetworkVersion, Call(precommit_key))
547-
.Times(2)
548583
.WillRepeatedly(testing::Return(outcome::success(version_)));
549-
EXPECT_OUTCOME_TRUE(duration,
550-
checks::getMaxProveCommitDuration(version_, info));
551-
ChainEpoch height = duration
552-
+ vm::actor::builtin::types::miner::kChainFinality
553-
+ info->ticket_epoch;
584+
585+
ChainEpoch height;
554586

555587
auto actor_key{"010001020003"_cid};
588+
556589
SectorPreCommitOnChainInfo some_info;
557590
some_info.info.sealed_cid = "010001020006"_cid;
591+
some_info.info.seal_epoch = info->ticket_epoch + 1;
558592
EXPECT_OUTCOME_TRUE_1(
559593
actor_state_->precommitted_sectors.set(sector, some_info));
560594
EXPECT_OUTCOME_TRUE(cid_root,
@@ -582,16 +616,16 @@ namespace fc::mining::checks {
582616
-> outcome::result<Actor> { return actor; };
583617

584618
EXPECT_OUTCOME_ERROR(
585-
ChecksError::kPrecommitOnChain,
619+
ChecksError::kBadTicketEpoch,
586620
checkPrecommit(miner_addr_, info, precommit_key, height, api_));
587621
}
588622

589623
/**
590-
* @given info, valid pieces, ticket, precommit on chain
591-
* @when try to check precommit, but ticket with another epoch
592-
* @then ChecksError::kBadTicketEpoch occurs
624+
* @given info, valid pieces, expired ticket
625+
* @when try to check precommit
626+
* @then ChecksError::kExpiredTicket occurs
593627
*/
594-
TEST_F(CheckPrecommit, BadTicketEpoch) {
628+
TEST_F(CheckPrecommit, ExpiredTicket) {
595629
std::shared_ptr<SectorInfo> info = std::make_shared<SectorInfo>();
596630
api::DealId deal_id = 1;
597631

@@ -651,21 +685,15 @@ namespace fc::mining::checks {
651685

652686
MOCK_API(api_, StateNetworkVersion);
653687
EXPECT_CALL(mock_StateNetworkVersion, Call(precommit_key))
654-
.Times(2)
655688
.WillRepeatedly(testing::Return(outcome::success(version_)));
656-
EXPECT_OUTCOME_TRUE(duration,
657-
checks::getMaxProveCommitDuration(version_, info));
658-
ChainEpoch height = duration
659-
+ vm::actor::builtin::types::miner::kChainFinality
660-
+ info->ticket_epoch;
661689

662690
auto actor_key{"010001020003"_cid};
663691

664692
SectorPreCommitOnChainInfo some_info;
665693
some_info.info.sealed_cid = "010001020006"_cid;
666694
some_info.info.seal_epoch = info->ticket_epoch + 1;
667695
EXPECT_OUTCOME_TRUE_1(
668-
actor_state_->precommitted_sectors.set(sector, some_info));
696+
actor_state_->precommitted_sectors.set(sector + 1, some_info));
669697
EXPECT_OUTCOME_TRUE(cid_root,
670698
actor_state_->precommitted_sectors.hamt.flush());
671699

@@ -690,8 +718,11 @@ namespace fc::mining::checks {
690718
api_->StateGetActor = [&](const Address &addr, const TipsetKey &tipset_key)
691719
-> outcome::result<Actor> { return actor; };
692720

721+
info->ticket_epoch = 0;
722+
ChainEpoch height =
723+
vm::actor::builtin::types::miner::kMaxPreCommitRandomnessLookback + 1;
693724
EXPECT_OUTCOME_ERROR(
694-
ChecksError::kBadTicketEpoch,
725+
ChecksError::kExpiredTicket,
695726
checkPrecommit(miner_addr_, info, precommit_key, height, api_));
696727
}
697728

0 commit comments

Comments
 (0)