@@ -68,6 +68,7 @@ namespace fc::api {
6868 using primitives::kChainEpochUndefined ;
6969 using primitives::block::MsgMeta;
7070 using primitives::sector::getPreferredSealProofTypeFromWindowPoStType;
71+ using primitives::tipset::HeadChangeType;
7172 using primitives::tipset::Tipset;
7273 using storage::ipld::kAllSelector ;
7374 using vm::isVMExitCode;
@@ -84,6 +85,7 @@ namespace fc::api {
8485 using vm::actor::builtin::states::RewardActorStatePtr;
8586 using vm::actor::builtin::states::VerifiedRegistryActorStatePtr;
8687 using vm::actor::builtin::types::market::DealState;
88+ using vm::actor::builtin::types::miner::kChainFinality ;
8789 using vm::actor::builtin::types::storage_power::kConsensusMinerMinPower ;
8890 using vm::interpreter::InterpreterCache;
8991 using vm::runtime::Env;
@@ -293,6 +295,27 @@ namespace fc::api {
293295 OUTCOME_TRY (cbor, ipld->get (cid));
294296 return UnsignedMessage::decode (cbor);
295297 };
298+ api->ChainGetPath = [=](const TipsetKey &from_key, const TipsetKey &to_key)
299+ -> outcome::result<std::vector<HeadChange>> {
300+ std::vector<HeadChange> revert;
301+ std::vector<HeadChange> apply;
302+ OUTCOME_TRY (from, ts_load->load (from_key));
303+ OUTCOME_TRY (to, ts_load->load (to_key));
304+ while (from->key != to->key ) {
305+ if (revert.size () > kChainFinality || apply.size () > kChainFinality ) {
306+ return ERROR_TEXT (" ChainGetPath finality limit" );
307+ }
308+ if (from->height () > to->height ()) {
309+ revert.emplace_back (HeadChange{HeadChangeType::REVERT, from});
310+ OUTCOME_TRYA (from, ts_load->load (from->getParents ()));
311+ } else {
312+ apply.emplace_back (HeadChange{HeadChangeType::APPLY, to});
313+ OUTCOME_TRYA (to, ts_load->load (to->getParents ()));
314+ }
315+ }
316+ revert.insert (revert.end (), apply.rbegin (), apply.rend ());
317+ return std::move (revert);
318+ };
296319 api->ChainGetParentMessages =
297320 [=](auto &block_cid) -> outcome::result<std::vector<CidMessage>> {
298321 std::vector<CidMessage> messages;
0 commit comments