Skip to content

Commit 8d2551a

Browse files
committed
Teach full node to response with split persistent states
We introduce two additional ADNL requests that can be made between nodes: downloadPersistentStateSliceV2 and getPersistentStateSizeV2. They differ from "V1" versions by inclusion of "effective shard" parameter. The parameter denotes a split account state if block.shard is a proper ancestor of effective_shard. If block.shard == effective_shard, we treat this as a request for split state header, and if it is 0 (or invalid), we serve an unsplit state. Old requests are wired to call V2 with effective shard set to 0.
1 parent 27a4b36 commit 8d2551a

File tree

7 files changed

+108
-25
lines changed

7 files changed

+108
-25
lines changed

tl/generate/scheme/ton_api.tl

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ tonNode.preparedProof = tonNode.PreparedProof;
409409
tonNode.preparedProofLink = tonNode.PreparedProof;
410410
tonNode.preparedState = tonNode.PreparedState;
411411
tonNode.notFoundState = tonNode.PreparedState;
412+
tonNode.persistentStateIdV2 block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt effective_shard:long = tonNode.PersistentStateIdV2;
412413
tonNode.persistentStateSize size:long = tonNode.PersistentStateSize;
413414
tonNode.persistentStateSizeNotFound = tonNode.PersistentStateSize;
414415
tonNode.prepared = tonNode.Prepared;
@@ -476,15 +477,11 @@ tonNode.prepareBlockProofs blocks:(vector tonNode.blockIdExt) allow_partial:Bool
476477
tonNode.prepareKeyBlockProofs blocks:(vector tonNode.blockIdExt) allow_partial:Bool = tonNode.PreparedProof;
477478
tonNode.prepareBlock block:tonNode.blockIdExt = tonNode.Prepared;
478479
tonNode.prepareBlocks blocks:(vector tonNode.blockIdExt) = tonNode.Prepared;
479-
tonNode.preparePersistentState block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt = tonNode.PreparedState;
480-
tonNode.getPersistentStateSize block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt = tonNode.PersistentStateSize;
481480
tonNode.prepareZeroState block:tonNode.blockIdExt = tonNode.PreparedState;
482481
tonNode.getNextKeyBlockIds block:tonNode.blockIdExt max_size:int = tonNode.KeyBlocks;
483482
tonNode.downloadNextBlockFull prev_block:tonNode.blockIdExt = tonNode.DataFull;
484483
tonNode.downloadBlockFull block:tonNode.blockIdExt = tonNode.DataFull;
485484
tonNode.downloadBlock block:tonNode.blockIdExt = tonNode.Data;
486-
tonNode.downloadPersistentState block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt = tonNode.Data;
487-
tonNode.downloadPersistentStateSlice block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt offset:long max_size:long = tonNode.Data;
488485
tonNode.downloadZeroState block:tonNode.blockIdExt = tonNode.Data;
489486
tonNode.downloadBlockProof block:tonNode.blockIdExt = tonNode.Data;
490487
tonNode.downloadKeyBlockProof block:tonNode.blockIdExt = tonNode.Data;
@@ -496,6 +493,14 @@ tonNode.getArchiveSlice archive_id:long offset:long max_size:int = tonNode.Data;
496493
tonNode.getOutMsgQueueProof dst_shard:tonNode.shardId blocks:(vector tonNode.blockIdExt)
497494
limits:tonNode.importedMsgQueueLimits = tonNode.OutMsgQueueProof;
498495

496+
tonNode.downloadPersistentState block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt = tonNode.Data;
497+
tonNode.downloadPersistentStateSlice block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt offset:long max_size:long = tonNode.Data;
498+
tonNode.getPersistentStateSize block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt = tonNode.PersistentStateSize;
499+
tonNode.preparePersistentState block:tonNode.blockIdExt masterchain_block:tonNode.blockIdExt = tonNode.PreparedState;
500+
501+
tonNode.downloadPersistentStateSliceV2 state:tonNode.persistentStateIdV2 offset:long max_size:long = tonNode.Data;
502+
tonNode.getPersistentStateSizeV2 state:tonNode.persistentStateIdV2 = tonNode.PersistentStateSize;
503+
499504
tonNode.getCapabilities = tonNode.Capabilities;
500505

501506
tonNode.slave.sendExtMessage message:tonNode.externalMessage = tonNode.Success;

tl/generate/scheme/ton_api.tlo

528 Bytes
Binary file not shown.

validator/full-node-master.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,12 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
291291
masterchain_block_id, UnsplitStateType{}, std::move(P));
292292
}
293293

294+
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getPersistentStateSize &query,
295+
td::Promise<td::BufferSlice> promise) {
296+
auto query_v2 = create_tl_object<ton_api::tonNode_getPersistentStateSizeV2>(persistent_state_id_from_v1_query(query));
297+
return process_query(src, *query_v2, std::move(promise));
298+
}
299+
294300
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextKeyBlockIds &query,
295301
td::Promise<td::BufferSlice> promise) {
296302
auto cnt = static_cast<td::uint32>(query.max_size_);
@@ -351,6 +357,13 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
351357
masterchain_block_id, UnsplitStateType{}, std::move(P));
352358
}
353359

360+
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query,
361+
td::Promise<td::BufferSlice> promise) {
362+
auto query_v2 = create_tl_object<ton_api::tonNode_downloadPersistentStateSliceV2>(
363+
persistent_state_id_from_v1_query(query), query.offset_, query.max_size_);
364+
return process_query(src, *query_v2, std::move(promise));
365+
}
366+
354367
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getCapabilities &query,
355368
td::Promise<td::BufferSlice> promise) {
356369
promise.set_value(
@@ -402,7 +415,8 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
402415
promise.set_value(create_serialize_tl_object<ton_api::tonNode_success>());
403416
}
404417

405-
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query,
418+
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src,
419+
ton_api::tonNode_downloadPersistentStateSliceV2 &query,
406420
td::Promise<td::BufferSlice> promise) {
407421
auto P = td::PromiseCreator::lambda(
408422
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
@@ -413,13 +427,12 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
413427

414428
promise.set_value(R.move_as_ok());
415429
});
416-
auto block_id = create_block_id(query.block_);
417-
auto masterchain_block_id = create_block_id(query.masterchain_block_);
430+
auto [block_id, mc_block_id, state_type] = persistent_state_from_v2_query(query);
418431
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state_slice, block_id,
419-
masterchain_block_id, UnsplitStateType{}, query.offset_, query.max_size_, std::move(P));
432+
mc_block_id, state_type, query.offset_, query.max_size_, std::move(P));
420433
}
421434

422-
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getPersistentStateSize &query,
435+
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getPersistentStateSizeV2 &query,
423436
td::Promise<td::BufferSlice> promise) {
424437
auto P = td::PromiseCreator::lambda(
425438
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::uint64> R) mutable {
@@ -429,10 +442,9 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
429442
promise.set_value(create_serialize_tl_object<ton_api::tonNode_persistentStateSize>(R.move_as_ok()));
430443
}
431444
});
432-
auto block_id = create_block_id(query.block_);
433-
auto masterchain_block_id = create_block_id(query.masterchain_block_);
445+
auto [block_id, mc_block_id, state_type] = persistent_state_from_v2_query(query);
434446
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state_size, block_id,
435-
masterchain_block_id, UnsplitStateType{}, std::move(P));
447+
mc_block_id, state_type, std::move(P));
436448
}
437449

438450
void FullNodeMasterImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,

validator/full-node-master.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ class FullNodeMasterImpl : public FullNodeMaster {
8686
td::Promise<td::BufferSlice> promise);
8787
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,
8888
td::Promise<td::BufferSlice> promise);
89+
90+
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSliceV2 &query,
91+
td::Promise<td::BufferSlice> promise);
92+
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getPersistentStateSizeV2 &query,
93+
td::Promise<td::BufferSlice> promise);
94+
8995
// void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareNextKeyBlockProof &query,
9096
// td::Promise<td::BufferSlice> promise);
9197
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise<td::BufferSlice> promise);

validator/full-node-shard.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,12 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
526526
masterchain_block_id, UnsplitStateType{}, std::move(P));
527527
}
528528

529+
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getPersistentStateSize &query,
530+
td::Promise<td::BufferSlice> promise) {
531+
auto query_v2 = create_tl_object<ton_api::tonNode_getPersistentStateSizeV2>(persistent_state_id_from_v1_query(query));
532+
return process_query(src, *query_v2, std::move(promise));
533+
}
534+
529535
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextKeyBlockIds &query,
530536
td::Promise<td::BufferSlice> promise) {
531537
auto cnt = static_cast<td::uint32>(query.max_size_);
@@ -595,6 +601,13 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
595601
masterchain_block_id, UnsplitStateType{}, 0, max_size + 1, std::move(P));
596602
}
597603

604+
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query,
605+
td::Promise<td::BufferSlice> promise) {
606+
auto query_v2 = create_tl_object<ton_api::tonNode_downloadPersistentStateSliceV2>(
607+
persistent_state_id_from_v1_query(query), query.offset_, query.max_size_);
608+
return process_query(src, *query_v2, std::move(promise));
609+
}
610+
598611
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getCapabilities &query,
599612
td::Promise<td::BufferSlice> promise) {
600613
VLOG(FULL_NODE_DEBUG) << "Got query getCapabilities from " << src;
@@ -702,13 +715,12 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
702715
});
703716
}
704717

705-
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query,
718+
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSliceV2 &query,
706719
td::Promise<td::BufferSlice> promise) {
707-
auto block_id = create_block_id(query.block_);
708-
auto masterchain_block_id = create_block_id(query.masterchain_block_);
709-
VLOG(FULL_NODE_DEBUG) << "Got query downloadPersistentStateSlice " << block_id.to_str() << " "
710-
<< masterchain_block_id.to_str() << " " << query.offset_ << " " << query.max_size_ << " from "
711-
<< src;
720+
auto [block_id, mc_block_id, state_type] = persistent_state_from_v2_query(query);
721+
VLOG(FULL_NODE_DEBUG) << "Got query downloadPersistentStateSlice " << block_id.to_str() << " " << mc_block_id.to_str()
722+
<< " (" << persistent_state_type_to_string(block_id.shard_full(), state_type) << ") "
723+
<< query.offset_ << " " << query.max_size_ << " from " << src;
712724
if (query.max_size_ < 0 || query.max_size_ > (1 << 24)) {
713725
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "invalid max_size"));
714726
return;
@@ -723,10 +735,10 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
723735
promise.set_value(R.move_as_ok());
724736
});
725737
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state_slice, block_id,
726-
masterchain_block_id, UnsplitStateType{}, query.offset_, query.max_size_, std::move(P));
738+
mc_block_id, state_type, query.offset_, query.max_size_, std::move(P));
727739
}
728740

729-
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getPersistentStateSize &query,
741+
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getPersistentStateSizeV2 &query,
730742
td::Promise<td::BufferSlice> promise) {
731743
auto P = td::PromiseCreator::lambda(
732744
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::uint64> R) mutable {
@@ -736,12 +748,12 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
736748
promise.set_value(create_serialize_tl_object<ton_api::tonNode_persistentStateSize>(R.move_as_ok()));
737749
}
738750
});
739-
auto block_id = create_block_id(query.block_);
740-
auto masterchain_block_id = create_block_id(query.masterchain_block_);
741-
VLOG(FULL_NODE_DEBUG) << "Got query getPersistentStateSize " << block_id.to_str() << " "
742-
<< masterchain_block_id.to_str() << " from " << src;
751+
auto [block_id, mc_block_id, state_type] = persistent_state_from_v2_query(query);
752+
VLOG(FULL_NODE_DEBUG) << "Got query getPersistentStateSize " << block_id.to_str() << " " << mc_block_id.to_str()
753+
<< " (" << persistent_state_type_to_string(block_id.shard_full(), state_type) << ") from "
754+
<< src;
743755
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state_size, block_id,
744-
masterchain_block_id, UnsplitStateType{}, std::move(P));
756+
mc_block_id, state_type, std::move(P));
745757
}
746758

747759
void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,

validator/full-node-shard.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ class FullNodeShardImpl : public FullNodeShard {
143143
td::Promise<td::BufferSlice> promise);
144144
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getOutMsgQueueProof &query,
145145
td::Promise<td::BufferSlice> promise);
146+
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSliceV2 &query,
147+
td::Promise<td::BufferSlice> promise);
148+
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getPersistentStateSizeV2 &query,
149+
td::Promise<td::BufferSlice> promise);
146150
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
147151
void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data);
148152

validator/interfaces/persistent-state.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616
*/
1717
#pragma once
1818

19+
#include "auto/tl/ton_api.h"
1920
#include "td/utils/Variant.h"
21+
#include "td/utils/overloaded.h"
2022
#include "ton/ton-types.h"
23+
#include "ton/ton-shard.h"
2124

2225
namespace ton {
2326

@@ -33,6 +36,47 @@ struct SplitPersistentStateType {};
3336

3437
using PersistentStateType = td::Variant<UnsplitStateType, SplitAccountStateType, SplitPersistentStateType>;
3538

39+
auto persistent_state_id_from_v1_query(auto const &query) {
40+
auto block = create_tl_block_id(create_block_id(query.block_));
41+
auto mc_block = create_tl_block_id(create_block_id(query.masterchain_block_));
42+
return create_tl_object<ton_api::tonNode_persistentStateIdV2>(std::move(block), std::move(mc_block), 0);
43+
}
44+
45+
auto persistent_state_from_v2_query(auto const &query) {
46+
auto block = create_block_id(query.state_->block_);
47+
auto mc_block = create_block_id(query.state_->masterchain_block_);
48+
ShardId effective_shard = static_cast<ShardId>(query.state_->effective_shard_);
49+
50+
if (effective_shard == 0 || !shard_is_ancestor(block.shard_full().shard, effective_shard)) {
51+
// The second condition is technically a "protocol" violation but since we don't really validate
52+
// stuff here regardless, let's just map it to an unsplit state.
53+
return std::tuple{block, mc_block, PersistentStateType{UnsplitStateType{}}};
54+
}
55+
56+
if (effective_shard == block.shard_full().shard) {
57+
return std::tuple{block, mc_block, PersistentStateType{SplitPersistentStateType{}}};
58+
}
59+
60+
CHECK(shard_is_proper_ancestor(block.shard_full().shard, effective_shard));
61+
return std::tuple{block, mc_block, PersistentStateType{SplitAccountStateType{effective_shard}}};
62+
}
63+
64+
inline std::string persistent_state_type_to_string(ShardIdFull const &shard, PersistentStateType const &state) {
65+
std::string result;
66+
state.visit(td::overloaded([&](UnsplitStateType) { result = "unsplit"; },
67+
[&](SplitAccountStateType type) {
68+
int real_pfx_len = shard_prefix_length(shard.shard);
69+
int effective_pfx_len = shard_prefix_length(type.effective_shard_id);
70+
td::uint64 parts_count = 1 << (effective_pfx_len - real_pfx_len);
71+
td::uint64 part_idx =
72+
type.effective_shard_id >> (64 - effective_pfx_len) & (parts_count - 1);
73+
result =
74+
"part " + std::to_string(part_idx + 1) + " out of " + std::to_string(parts_count);
75+
},
76+
[&](SplitPersistentStateType) { result = "split header"; }));
77+
return result;
78+
}
79+
3680
} // namespace validator
3781

3882
} // namespace ton

0 commit comments

Comments
 (0)