mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated tonlib, fixed bugs
updated tonlib fixed bugs in func validator: partial support for hardforks liteserver: support for waitMasterchainBlock prefix transactions: support for gas flat rate
This commit is contained in:
parent
841d5ebac2
commit
7ea00ebfcf
89 changed files with 1922 additions and 608 deletions
|
@ -1143,6 +1143,20 @@ bool TrStoragePhase::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||||
&& t_AccStatusChange.validate_skip(cs, weak); // status_change:AccStatusChange
|
&& t_AccStatusChange.validate_skip(cs, weak); // status_change:AccStatusChange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TrStoragePhase::get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const {
|
||||||
|
return t_Grams.as_integer_skip_to(cs, storage_fees); // storage_fees_collected:Grams
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TrStoragePhase::maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const {
|
||||||
|
auto z = cs.fetch_ulong(1);
|
||||||
|
if (!z) {
|
||||||
|
storage_fees = td::make_refint(0);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return z == 1 && get_storage_fees(cs, storage_fees);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const TrStoragePhase t_TrStoragePhase;
|
const TrStoragePhase t_TrStoragePhase;
|
||||||
|
|
||||||
bool TrCreditPhase::skip(vm::CellSlice& cs) const {
|
bool TrCreditPhase::skip(vm::CellSlice& cs) const {
|
||||||
|
@ -1322,13 +1336,14 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const {
|
||||||
&& t_TrStoragePhase.skip(cs); // storage_ph:TrStoragePhase
|
&& t_TrStoragePhase.skip(cs); // storage_ph:TrStoragePhase
|
||||||
case trans_tick_tock:
|
case trans_tick_tock:
|
||||||
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
||||||
&& t_TrStoragePhase.skip(cs) // storage:TrStoragePhase
|
&& t_TrStoragePhase.skip(cs) // storage_ph:TrStoragePhase
|
||||||
&& t_TrComputePhase.skip(cs) // compute_ph:TrComputePhase
|
&& t_TrComputePhase.skip(cs) // compute_ph:TrComputePhase
|
||||||
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
||||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||||
case trans_split_prepare:
|
case trans_split_prepare:
|
||||||
return cs.advance(4) // trans_split_prepare$0100
|
return cs.advance(4) // trans_split_prepare$0100
|
||||||
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||||
|
&& Maybe<TrStoragePhase>{}.skip(cs) // storage_ph:(Maybe TrStoragePhase)
|
||||||
&& t_TrComputePhase.skip(cs) // compute_ph:TrComputePhase
|
&& t_TrComputePhase.skip(cs) // compute_ph:TrComputePhase
|
||||||
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
||||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||||
|
@ -1346,6 +1361,7 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const {
|
||||||
return cs.advance(4) // trans_merge_install$0111
|
return cs.advance(4) // trans_merge_install$0111
|
||||||
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||||
&& t_Ref_Transaction.skip(cs) // prepare_transaction:^Transaction
|
&& t_Ref_Transaction.skip(cs) // prepare_transaction:^Transaction
|
||||||
|
&& Maybe<TrStoragePhase>{}.skip(cs) // storage_ph:(Maybe TrStoragePhase)
|
||||||
&& Maybe<TrCreditPhase>{}.skip(cs) // credit_ph:(Maybe TrCreditPhase)
|
&& Maybe<TrCreditPhase>{}.skip(cs) // credit_ph:(Maybe TrCreditPhase)
|
||||||
&& Maybe<TrComputePhase>{}.skip(cs) // compute_ph:TrComputePhase
|
&& Maybe<TrComputePhase>{}.skip(cs) // compute_ph:TrComputePhase
|
||||||
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
&& Maybe<RefTo<TrActionPhase>>{}.skip(cs) // action:(Maybe ^TrActionPhase)
|
||||||
|
@ -1370,13 +1386,14 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||||
&& t_TrStoragePhase.validate_skip(cs, weak); // storage_ph:TrStoragePhase
|
&& t_TrStoragePhase.validate_skip(cs, weak); // storage_ph:TrStoragePhase
|
||||||
case trans_tick_tock:
|
case trans_tick_tock:
|
||||||
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
||||||
&& t_TrStoragePhase.validate_skip(cs, weak) // storage:TrStoragePhase
|
&& t_TrStoragePhase.validate_skip(cs, weak) // storage_ph:TrStoragePhase
|
||||||
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||||
case trans_split_prepare:
|
case trans_split_prepare:
|
||||||
return cs.advance(4) // trans_split_prepare$0100
|
return cs.advance(4) // trans_split_prepare$0100
|
||||||
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
||||||
|
&& Maybe<TrStoragePhase>{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||||
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||||
|
@ -1394,6 +1411,7 @@ bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||||
return cs.advance(4) // trans_merge_install$0111
|
return cs.advance(4) // trans_merge_install$0111
|
||||||
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
||||||
&& t_Ref_Transaction.validate_skip(cs, weak) // prepare_transaction:^Transaction
|
&& t_Ref_Transaction.validate_skip(cs, weak) // prepare_transaction:^Transaction
|
||||||
|
&& Maybe<TrStoragePhase>{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||||
&& Maybe<TrCreditPhase>{}.validate_skip(cs, weak) // credit_ph:(Maybe TrCreditPhase)
|
&& Maybe<TrCreditPhase>{}.validate_skip(cs, weak) // credit_ph:(Maybe TrCreditPhase)
|
||||||
&& Maybe<TrComputePhase>{}.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
&& Maybe<TrComputePhase>{}.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||||
|
@ -1407,6 +1425,53 @@ int TransactionDescr::get_tag(const vm::CellSlice& cs) const {
|
||||||
return (t >= 0 && t <= 7) ? (t == 3 ? 2 : t) : -1;
|
return (t >= 0 && t <= 7) ? (t == 3 ? 2 : t) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TransactionDescr::skip_to_storage_phase(vm::CellSlice& cs, bool& found) const {
|
||||||
|
found = false;
|
||||||
|
switch (get_tag(cs)) {
|
||||||
|
case trans_ord:
|
||||||
|
return cs.advance(4 + 1) // trans_ord$0000 storage_first:Bool
|
||||||
|
&& cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase)
|
||||||
|
case trans_storage:
|
||||||
|
return cs.advance(4) // trans_storage$0001
|
||||||
|
&& (found = true); // storage_ph:TrStoragePhase
|
||||||
|
case trans_tick_tock:
|
||||||
|
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
||||||
|
&& (found = true); // storage_ph:TrStoragePhase
|
||||||
|
case trans_split_prepare:
|
||||||
|
return cs.advance(4) // trans_split_prepare$0100
|
||||||
|
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||||
|
&& cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase)
|
||||||
|
case trans_split_install:
|
||||||
|
return true;
|
||||||
|
case trans_merge_prepare:
|
||||||
|
return cs.advance(4) // trans_merge_prepare$0110
|
||||||
|
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||||
|
&& (found = true); // storage_ph:TrStoragePhase
|
||||||
|
case trans_merge_install:
|
||||||
|
return cs.advance(4) // trans_merge_install$0111
|
||||||
|
&& t_SplitMergeInfo.skip(cs) // split_info:SplitMergeInfo
|
||||||
|
&& t_Ref_Transaction.skip(cs) // prepare_transaction:^Transaction
|
||||||
|
&& cs.fetch_bool_to(found); // storage_ph:(Maybe TrStoragePhase)
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransactionDescr::get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const {
|
||||||
|
if (cell.is_null()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto cs = vm::load_cell_slice(std::move(cell));
|
||||||
|
bool found;
|
||||||
|
if (!skip_to_storage_phase(cs, found)) {
|
||||||
|
return false;
|
||||||
|
} else if (found) {
|
||||||
|
return t_TrStoragePhase.get_storage_fees(cs, storage_fees);
|
||||||
|
} else {
|
||||||
|
storage_fees = td::make_refint(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const TransactionDescr t_TransactionDescr;
|
const TransactionDescr t_TransactionDescr;
|
||||||
|
|
||||||
bool Transaction_aux::skip(vm::CellSlice& cs) const {
|
bool Transaction_aux::skip(vm::CellSlice& cs) const {
|
||||||
|
@ -1447,6 +1512,32 @@ bool Transaction::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||||
&& RefTo<TransactionDescr>{}.validate_skip(cs, weak); // description:^TransactionDescr
|
&& RefTo<TransactionDescr>{}.validate_skip(cs, weak); // description:^TransactionDescr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Transaction::get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const {
|
||||||
|
Ref<vm::Cell> tdescr;
|
||||||
|
return get_descr(std::move(cell), tdescr) && t_TransactionDescr.get_storage_fees(std::move(tdescr), storage_fees);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Transaction::get_descr(Ref<vm::Cell> cell, Ref<vm::Cell>& tdescr) const {
|
||||||
|
if (cell.is_null()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
auto cs = vm::load_cell_slice(std::move(cell));
|
||||||
|
return cs.is_valid() && get_descr(cs, tdescr) && cs.empty_ext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Transaction::get_descr(vm::CellSlice& cs, Ref<vm::Cell>& tdescr) const {
|
||||||
|
return cs.advance(
|
||||||
|
4 + 256 + 64 + 256 + 64 + 32 +
|
||||||
|
15) // transaction$0111 account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15
|
||||||
|
&& t_AccountStatus.skip(cs) // orig_status:AccountStatus
|
||||||
|
&& t_AccountStatus.skip(cs) // end_status:AccountStatus
|
||||||
|
&& cs.advance_refs(1) // ^[ in_msg:(Maybe ^Message) out_msgs:(HashmapE 15 ^Message) ]
|
||||||
|
&& t_CurrencyCollection.skip(cs) // total_fees:CurrencyCollection
|
||||||
|
&& cs.advance_refs(1) // state_update:^(MERKLE_UPDATE Account)
|
||||||
|
&& cs.fetch_ref_to(tdescr); // description:^TransactionDescr
|
||||||
|
}
|
||||||
|
|
||||||
bool Transaction::get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const {
|
bool Transaction::get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const {
|
||||||
return cs.is_valid() && cs.fetch_ulong(4) == 7 // transaction$0111
|
return cs.is_valid() && cs.fetch_ulong(4) == 7 // transaction$0111
|
||||||
&&
|
&&
|
||||||
|
|
|
@ -614,6 +614,8 @@ extern const AccStatusChange t_AccStatusChange;
|
||||||
struct TrStoragePhase final : TLB_Complex {
|
struct TrStoragePhase final : TLB_Complex {
|
||||||
bool skip(vm::CellSlice& cs) const override;
|
bool skip(vm::CellSlice& cs) const override;
|
||||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||||
|
bool get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const;
|
||||||
|
bool maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const TrStoragePhase t_TrStoragePhase;
|
extern const TrStoragePhase t_TrStoragePhase;
|
||||||
|
@ -693,6 +695,8 @@ struct TransactionDescr final : TLB_Complex {
|
||||||
bool skip(vm::CellSlice& cs) const override;
|
bool skip(vm::CellSlice& cs) const override;
|
||||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||||
int get_tag(const vm::CellSlice& cs) const override;
|
int get_tag(const vm::CellSlice& cs) const override;
|
||||||
|
bool skip_to_storage_phase(vm::CellSlice& cs, bool& found) const;
|
||||||
|
bool get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const TransactionDescr t_TransactionDescr;
|
extern const TransactionDescr t_TransactionDescr;
|
||||||
|
@ -708,6 +712,9 @@ struct Transaction final : TLB_Complex {
|
||||||
bool skip(vm::CellSlice& cs) const override;
|
bool skip(vm::CellSlice& cs) const override;
|
||||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||||
bool get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const;
|
bool get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const;
|
||||||
|
bool get_descr(Ref<vm::Cell> cell, Ref<vm::Cell>& tdescr) const;
|
||||||
|
bool get_descr(vm::CellSlice& cs, Ref<vm::Cell>& tdescr) const;
|
||||||
|
bool get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const Transaction t_Transaction;
|
extern const Transaction t_Transaction;
|
||||||
|
|
|
@ -325,7 +325,7 @@ trans_ord$0000 credit_first:Bool
|
||||||
trans_storage$0001 storage_ph:TrStoragePhase
|
trans_storage$0001 storage_ph:TrStoragePhase
|
||||||
= TransactionDescr;
|
= TransactionDescr;
|
||||||
|
|
||||||
trans_tick_tock$001 is_tock:Bool storage:TrStoragePhase
|
trans_tick_tock$001 is_tock:Bool storage_ph:TrStoragePhase
|
||||||
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
||||||
aborted:Bool destroyed:Bool = TransactionDescr;
|
aborted:Bool destroyed:Bool = TransactionDescr;
|
||||||
//
|
//
|
||||||
|
@ -333,6 +333,7 @@ split_merge_info$_ cur_shard_pfx_len:(## 6)
|
||||||
acc_split_depth:(## 6) this_addr:bits256 sibling_addr:bits256
|
acc_split_depth:(## 6) this_addr:bits256 sibling_addr:bits256
|
||||||
= SplitMergeInfo;
|
= SplitMergeInfo;
|
||||||
trans_split_prepare$0100 split_info:SplitMergeInfo
|
trans_split_prepare$0100 split_info:SplitMergeInfo
|
||||||
|
storage_ph:(Maybe TrStoragePhase)
|
||||||
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
||||||
aborted:Bool destroyed:Bool
|
aborted:Bool destroyed:Bool
|
||||||
= TransactionDescr;
|
= TransactionDescr;
|
||||||
|
@ -345,6 +346,7 @@ trans_merge_prepare$0110 split_info:SplitMergeInfo
|
||||||
= TransactionDescr;
|
= TransactionDescr;
|
||||||
trans_merge_install$0111 split_info:SplitMergeInfo
|
trans_merge_install$0111 split_info:SplitMergeInfo
|
||||||
prepare_transaction:^Transaction
|
prepare_transaction:^Transaction
|
||||||
|
storage_ph:(Maybe TrStoragePhase)
|
||||||
credit_ph:(Maybe TrCreditPhase)
|
credit_ph:(Maybe TrCreditPhase)
|
||||||
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
compute_ph:TrComputePhase action:(Maybe ^TrActionPhase)
|
||||||
aborted:Bool destroyed:Bool
|
aborted:Bool destroyed:Bool
|
||||||
|
@ -609,6 +611,9 @@ gas_prices_ext#de gas_price:uint64 gas_limit:uint64 special_gas_limit:uint64 gas
|
||||||
block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64
|
block_gas_limit:uint64 freeze_due_limit:uint64 delete_due_limit:uint64
|
||||||
= GasLimitsPrices;
|
= GasLimitsPrices;
|
||||||
|
|
||||||
|
gas_flat_pfx#d1 flat_gas_limit:uint64 flat_gas_price:uint64 other:GasLimitsPrices
|
||||||
|
= GasLimitsPrices;
|
||||||
|
|
||||||
config_mc_gas_prices#_ GasLimitsPrices = ConfigParam 20;
|
config_mc_gas_prices#_ GasLimitsPrices = ConfigParam 20;
|
||||||
config_gas_prices#_ GasLimitsPrices = ConfigParam 21;
|
config_gas_prices#_ GasLimitsPrices = ConfigParam 21;
|
||||||
|
|
||||||
|
|
|
@ -672,9 +672,56 @@ bool Transaction::prepare_credit_phase() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ComputePhaseConfig::parse_GasLimitsPrices(Ref<vm::Cell> cell, td::RefInt256& freeze_due_limit,
|
||||||
|
td::RefInt256& delete_due_limit) {
|
||||||
|
return cell.not_null() &&
|
||||||
|
parse_GasLimitsPrices(vm::load_cell_slice_ref(std::move(cell)), freeze_due_limit, delete_due_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ComputePhaseConfig::parse_GasLimitsPrices(Ref<vm::CellSlice> cs, td::RefInt256& freeze_due_limit,
|
||||||
|
td::RefInt256& delete_due_limit) {
|
||||||
|
if (cs.is_null()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
block::gen::GasLimitsPrices::Record_gas_flat_pfx flat;
|
||||||
|
if (tlb::csr_unpack(cs, flat)) {
|
||||||
|
bool ok = parse_GasLimitsPrices(std::move(flat.other), freeze_due_limit, delete_due_limit);
|
||||||
|
flat_gas_limit = flat.flat_gas_limit;
|
||||||
|
flat_gas_price = flat.flat_gas_price;
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
flat_gas_limit = flat_gas_price = 0;
|
||||||
|
auto f = [&](const auto& r, td::uint64 spec_limit) {
|
||||||
|
gas_limit = r.gas_limit;
|
||||||
|
special_gas_limit = spec_limit;
|
||||||
|
gas_credit = r.gas_credit;
|
||||||
|
gas_price = r.gas_price;
|
||||||
|
freeze_due_limit = td::RefInt256{true, r.freeze_due_limit};
|
||||||
|
delete_due_limit = td::RefInt256{true, r.delete_due_limit};
|
||||||
|
};
|
||||||
|
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
|
||||||
|
if (tlb::csr_unpack(cs, rec)) {
|
||||||
|
f(rec, rec.special_gas_limit);
|
||||||
|
} else {
|
||||||
|
block::gen::GasLimitsPrices::Record_gas_prices rec0;
|
||||||
|
if (tlb::csr_unpack(std::move(cs), rec0)) {
|
||||||
|
f(rec0, rec0.gas_limit);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compute_threshold();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void ComputePhaseConfig::compute_threshold() {
|
void ComputePhaseConfig::compute_threshold() {
|
||||||
gas_price256 = td::RefInt256{true, gas_price};
|
gas_price256 = td::RefInt256{true, gas_price};
|
||||||
max_gas_threshold = td::rshift(gas_price256 * gas_limit, 16, 1);
|
if (gas_limit > flat_gas_limit) {
|
||||||
|
max_gas_threshold =
|
||||||
|
td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_refint(flat_gas_price);
|
||||||
|
} else {
|
||||||
|
max_gas_threshold = td::make_refint(flat_gas_price);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td::uint64 ComputePhaseConfig::gas_bought_for(td::RefInt256 nanograms) const {
|
td::uint64 ComputePhaseConfig::gas_bought_for(td::RefInt256 nanograms) const {
|
||||||
|
@ -684,8 +731,11 @@ td::uint64 ComputePhaseConfig::gas_bought_for(td::RefInt256 nanograms) const {
|
||||||
if (nanograms >= max_gas_threshold) {
|
if (nanograms >= max_gas_threshold) {
|
||||||
return gas_limit;
|
return gas_limit;
|
||||||
}
|
}
|
||||||
auto res = td::div(std::move(nanograms) << 16, gas_price256);
|
if (nanograms < flat_gas_price) {
|
||||||
return res->to_long();
|
return 0;
|
||||||
|
}
|
||||||
|
auto res = td::div((std::move(nanograms) - flat_gas_price) << 16, gas_price256);
|
||||||
|
return res->to_long() + flat_gas_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
|
td::RefInt256 ComputePhaseConfig::compute_gas_price(td::uint64 gas_used) const {
|
||||||
|
@ -855,6 +905,16 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
||||||
cp.skip_reason = ComputePhase::sk_no_gas;
|
cp.skip_reason = ComputePhase::sk_no_gas;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// Compute gas limits
|
||||||
|
if (!compute_gas_limits(cp, cfg)) {
|
||||||
|
compute_phase.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!cp.gas_limit && !cp.gas_credit) {
|
||||||
|
// no gas
|
||||||
|
cp.skip_reason = ComputePhase::sk_no_gas;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (in_msg_state.not_null()) {
|
if (in_msg_state.not_null()) {
|
||||||
LOG(DEBUG) << "HASH(in_msg_state) = " << in_msg_state->get_hash().bits().to_hex(256)
|
LOG(DEBUG) << "HASH(in_msg_state) = " << in_msg_state->get_hash().bits().to_hex(256)
|
||||||
<< ", account_state_hash = " << account.state_hash.to_hex();
|
<< ", account_state_hash = " << account.state_hash.to_hex();
|
||||||
|
@ -883,11 +943,6 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
||||||
} else if (in_msg_state.not_null()) {
|
} else if (in_msg_state.not_null()) {
|
||||||
unpack_msg_state(true); // use only libraries
|
unpack_msg_state(true); // use only libraries
|
||||||
}
|
}
|
||||||
// Compute gas limits
|
|
||||||
if (!compute_gas_limits(cp, cfg)) {
|
|
||||||
compute_phase.reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// initialize VM
|
// initialize VM
|
||||||
Ref<vm::Stack> stack = prepare_vm_stack(cp);
|
Ref<vm::Stack> stack = prepare_vm_stack(cp);
|
||||||
if (stack.is_null()) {
|
if (stack.is_null()) {
|
||||||
|
|
|
@ -98,6 +98,8 @@ struct ComputePhaseConfig {
|
||||||
td::uint64 gas_limit;
|
td::uint64 gas_limit;
|
||||||
td::uint64 special_gas_limit;
|
td::uint64 special_gas_limit;
|
||||||
td::uint64 gas_credit;
|
td::uint64 gas_credit;
|
||||||
|
td::uint64 flat_gas_limit = 0;
|
||||||
|
td::uint64 flat_gas_price = 0;
|
||||||
static constexpr td::uint64 gas_infty = (1ULL << 63) - 1;
|
static constexpr td::uint64 gas_infty = (1ULL << 63) - 1;
|
||||||
td::RefInt256 gas_price256;
|
td::RefInt256 gas_price256;
|
||||||
td::RefInt256 max_gas_threshold;
|
td::RefInt256 max_gas_threshold;
|
||||||
|
@ -126,6 +128,8 @@ struct ComputePhaseConfig {
|
||||||
Ref<vm::Cell> get_lib_root() const {
|
Ref<vm::Cell> get_lib_root() const {
|
||||||
return libraries ? libraries->get_root_cell() : Ref<vm::Cell>{};
|
return libraries ? libraries->get_root_cell() : Ref<vm::Cell>{};
|
||||||
}
|
}
|
||||||
|
bool parse_GasLimitsPrices(Ref<vm::CellSlice> cs, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit);
|
||||||
|
bool parse_GasLimitsPrices(Ref<vm::Cell> cell, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit);
|
||||||
};
|
};
|
||||||
|
|
||||||
// msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
|
// msg_fwd_fees = (lump_price + ceil((bit_price * msg.bits + cell_price * msg.cells)/2^16)) nanograms
|
||||||
|
|
|
@ -764,6 +764,10 @@ void interpret_string_to_bytes(vm::Stack& stack) {
|
||||||
stack.push_bytes(stack.pop_string());
|
stack.push_bytes(stack.pop_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void interpret_bytes_to_string(vm::Stack& stack) {
|
||||||
|
stack.push_string(stack.pop_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
void interpret_bytes_hash(vm::Stack& stack, bool as_uint) {
|
void interpret_bytes_hash(vm::Stack& stack, bool as_uint) {
|
||||||
std::string str = stack.pop_bytes();
|
std::string str = stack.pop_bytes();
|
||||||
unsigned char buffer[32];
|
unsigned char buffer[32];
|
||||||
|
@ -796,7 +800,9 @@ void interpret_store_str(vm::Stack& stack) {
|
||||||
stack.check_underflow(2);
|
stack.check_underflow(2);
|
||||||
auto str = stack.pop_string();
|
auto str = stack.pop_string();
|
||||||
auto cell = stack.pop_builder();
|
auto cell = stack.pop_builder();
|
||||||
cell.write().store_bytes(str); // may throw CellWriteError
|
if (!cell.write().store_bytes_bool(str)) {
|
||||||
|
throw IntError{"string does not fit into cell"};
|
||||||
|
}
|
||||||
stack.push(cell);
|
stack.push(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -804,14 +810,18 @@ void interpret_store_bytes(vm::Stack& stack) {
|
||||||
stack.check_underflow(2);
|
stack.check_underflow(2);
|
||||||
auto str = stack.pop_bytes();
|
auto str = stack.pop_bytes();
|
||||||
auto cell = stack.pop_builder();
|
auto cell = stack.pop_builder();
|
||||||
cell.write().store_bytes(str); // may throw CellWriteError
|
if (!cell.write().store_bytes_bool(str)) {
|
||||||
|
throw IntError{"byte string does not fit into cell"};
|
||||||
|
}
|
||||||
stack.push(cell);
|
stack.push(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void interpret_string_to_cellslice(vm::Stack& stack) {
|
void interpret_string_to_cellslice(vm::Stack& stack) {
|
||||||
auto str = stack.pop_string();
|
auto str = stack.pop_string();
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
cb.store_bytes(str); // may throw CellWriteError
|
if (!cb.store_bytes_bool(str)) {
|
||||||
|
throw IntError{"string does not fit into cell"};
|
||||||
|
}
|
||||||
stack.push_cellslice(td::Ref<vm::CellSlice>{true, cb.finalize()});
|
stack.push_cellslice(td::Ref<vm::CellSlice>{true, cb.finalize()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,7 +829,9 @@ void interpret_store_cellslice(vm::Stack& stack) {
|
||||||
stack.check_underflow(2);
|
stack.check_underflow(2);
|
||||||
auto cs = stack.pop_cellslice();
|
auto cs = stack.pop_cellslice();
|
||||||
auto cb = stack.pop_builder();
|
auto cb = stack.pop_builder();
|
||||||
vm::cell_builder_add_slice(cb.write(), *cs);
|
if (!vm::cell_builder_add_slice_bool(cb.write(), *cs)) {
|
||||||
|
throw IntError{"slice does not fit into cell"};
|
||||||
|
}
|
||||||
stack.push(std::move(cb));
|
stack.push(std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,9 +852,11 @@ void interpret_concat_cellslice(vm::Stack& stack) {
|
||||||
auto cs2 = stack.pop_cellslice();
|
auto cs2 = stack.pop_cellslice();
|
||||||
auto cs1 = stack.pop_cellslice();
|
auto cs1 = stack.pop_cellslice();
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
vm::cell_builder_add_slice(cb, *cs1);
|
if (vm::cell_builder_add_slice_bool(cb, *cs1) && vm::cell_builder_add_slice_bool(cb, *cs2)) {
|
||||||
vm::cell_builder_add_slice(cb, *cs2);
|
stack.push_cellslice(td::Ref<vm::CellSlice>{true, cb.finalize()});
|
||||||
stack.push_cellslice(td::Ref<vm::CellSlice>{true, cb.finalize()});
|
} else {
|
||||||
|
throw IntError{"concatenation of two slices does not fit into a cell"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void interpret_concat_cellslice_ref(vm::Stack& stack) {
|
void interpret_concat_cellslice_ref(vm::Stack& stack) {
|
||||||
|
@ -862,7 +876,9 @@ void interpret_concat_builders(vm::Stack& stack) {
|
||||||
stack.check_underflow(2);
|
stack.check_underflow(2);
|
||||||
auto cb2 = stack.pop_builder();
|
auto cb2 = stack.pop_builder();
|
||||||
auto cb1 = stack.pop_builder();
|
auto cb1 = stack.pop_builder();
|
||||||
cb1.write().append_builder(std::move(cb2));
|
if (!cb1.write().append_builder_bool(std::move(cb2))) {
|
||||||
|
throw IntError{"cannot concatenate two builders"};
|
||||||
|
}
|
||||||
stack.push_builder(std::move(cb1));
|
stack.push_builder(std::move(cb1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2490,6 +2506,7 @@ void init_words_common(Dictionary& d) {
|
||||||
d.def_stack_word("B>Lu@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x12));
|
d.def_stack_word("B>Lu@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x12));
|
||||||
d.def_stack_word("B>Li@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x13));
|
d.def_stack_word("B>Li@+ ", std::bind(interpret_bytes_fetch_int, _1, 0x13));
|
||||||
d.def_stack_word("$>B ", interpret_string_to_bytes);
|
d.def_stack_word("$>B ", interpret_string_to_bytes);
|
||||||
|
d.def_stack_word("B>$ ", interpret_bytes_to_string);
|
||||||
d.def_stack_word("Bhash ", std::bind(interpret_bytes_hash, _1, true));
|
d.def_stack_word("Bhash ", std::bind(interpret_bytes_hash, _1, true));
|
||||||
d.def_stack_word("Bhashu ", std::bind(interpret_bytes_hash, _1, true));
|
d.def_stack_word("Bhashu ", std::bind(interpret_bytes_hash, _1, true));
|
||||||
d.def_stack_word("BhashB ", std::bind(interpret_bytes_hash, _1, false));
|
d.def_stack_word("BhashB ", std::bind(interpret_bytes_hash, _1, false));
|
||||||
|
|
|
@ -149,6 +149,10 @@ AsmOp AsmOp::IntConst(td::RefInt256 x) {
|
||||||
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT");
|
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AsmOp AsmOp::BoolConst(bool f) {
|
||||||
|
return AsmOp::Const(f ? "TRUE" : "FALSE");
|
||||||
|
}
|
||||||
|
|
||||||
AsmOp AsmOp::Parse(std::string custom_op) {
|
AsmOp AsmOp::Parse(std::string custom_op) {
|
||||||
if (custom_op == "NOP") {
|
if (custom_op == "NOP") {
|
||||||
return AsmOp::Nop();
|
return AsmOp::Nop();
|
||||||
|
|
|
@ -620,7 +620,7 @@ int compute_compare(td::RefInt256 x, td::RefInt256 y, int mode) {
|
||||||
if (mode == 7) {
|
if (mode == 7) {
|
||||||
return s;
|
return s;
|
||||||
} else {
|
} else {
|
||||||
return (mode >> (1 - s)) & 1;
|
return -((mode >> (1 - s)) & 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,8 +641,8 @@ int compute_compare(const VarDescr& x, const VarDescr& y, int mode) {
|
||||||
return x.always_less(y) ? 1 : (x.always_geq(y) ? 2 : 3);
|
return x.always_less(y) ? 1 : (x.always_geq(y) ? 2 : 3);
|
||||||
case 5: // <>
|
case 5: // <>
|
||||||
return x.always_neq(y) ? 1 : (x.always_equal(y) ? 2 : 3);
|
return x.always_neq(y) ? 1 : (x.always_equal(y) ? 2 : 3);
|
||||||
case 6: // >=
|
case 6: // <=
|
||||||
return x.always_geq(y) ? 1 : (x.always_less(y) ? 2 : 3);
|
return x.always_leq(y) ? 1 : (x.always_greater(y) ? 2 : 3);
|
||||||
case 7: // <=>
|
case 7: // <=>
|
||||||
return x.always_less(y)
|
return x.always_less(y)
|
||||||
? 1
|
? 1
|
||||||
|
@ -661,10 +661,11 @@ AsmOp compile_cmp_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args, i
|
||||||
assert(res.size() == 1 && args.size() == 2);
|
assert(res.size() == 1 && args.size() == 2);
|
||||||
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||||
if (x.is_int_const() && y.is_int_const()) {
|
if (x.is_int_const() && y.is_int_const()) {
|
||||||
r.set_const(compute_compare(x.int_const, y.int_const, mode));
|
int v = compute_compare(x.int_const, y.int_const, mode);
|
||||||
|
r.set_const(v);
|
||||||
x.unused();
|
x.unused();
|
||||||
y.unused();
|
y.unused();
|
||||||
return push_const(r.int_const);
|
return mode == 7 ? push_const(r.int_const) : AsmOp::BoolConst(v != 0);
|
||||||
}
|
}
|
||||||
int v = compute_compare(x, y, mode);
|
int v = compute_compare(x, y, mode);
|
||||||
assert(v);
|
assert(v);
|
||||||
|
@ -672,7 +673,7 @@ AsmOp compile_cmp_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args, i
|
||||||
r.set_const(v - (v >> 2) - 2);
|
r.set_const(v - (v >> 2) - 2);
|
||||||
x.unused();
|
x.unused();
|
||||||
y.unused();
|
y.unused();
|
||||||
return push_const(r.int_const);
|
return mode == 7 ? push_const(r.int_const) : AsmOp::BoolConst(v & 1);
|
||||||
}
|
}
|
||||||
r.val = ~0;
|
r.val = ~0;
|
||||||
if (v & 1) {
|
if (v & 1) {
|
||||||
|
@ -957,12 +958,11 @@ void define_builtins() {
|
||||||
AsmOp::Nop());
|
AsmOp::Nop());
|
||||||
define_builtin_func("~dump", TypeExpr::new_forall({X}, TypeExpr::new_map(X, TypeExpr::new_tensor({X, Unit}))),
|
define_builtin_func("~dump", TypeExpr::new_forall({X}, TypeExpr::new_map(X, TypeExpr::new_tensor({X, Unit}))),
|
||||||
AsmOp::Custom("s0 DUMP", 1, 1));
|
AsmOp::Custom("s0 DUMP", 1, 1));
|
||||||
define_builtin_func(
|
define_builtin_func("run_method0", TypeExpr::new_map(Int, Unit),
|
||||||
"run_method0", TypeExpr::new_map(Int, Unit),
|
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 0, false); }, true);
|
||||||
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 0, false); }, true);
|
define_builtin_func_x("run_method1",
|
||||||
define_builtin_func_x(
|
TypeExpr::new_forall({X}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X}), Unit)),
|
||||||
"run_method1", TypeExpr::new_forall({X}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X}), Unit)),
|
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 1, false); }, {1, 0}, {}, true);
|
||||||
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 1, false); }, {1, 0}, {}, true);
|
|
||||||
define_builtin_func_x(
|
define_builtin_func_x(
|
||||||
"run_method2", TypeExpr::new_forall({X, Y}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X, Y}), Unit)),
|
"run_method2", TypeExpr::new_forall({X, Y}, TypeExpr::new_map(TypeExpr::new_tensor({Int, X, Y}), Unit)),
|
||||||
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 2, false); }, {1, 2, 0}, {}, true);
|
[](auto a, auto b, auto c) { return compile_run_method(a, b, c, 2, false); }, {1, 2, 0}, {}, true);
|
||||||
|
|
|
@ -950,6 +950,7 @@ struct AsmOp {
|
||||||
static AsmOp make_stk2(int a, int b, const char* str, int delta);
|
static AsmOp make_stk2(int a, int b, const char* str, int delta);
|
||||||
static AsmOp make_stk3(int a, int b, int c, const char* str, int delta);
|
static AsmOp make_stk3(int a, int b, int c, const char* str, int delta);
|
||||||
static AsmOp IntConst(td::RefInt256 value);
|
static AsmOp IntConst(td::RefInt256 value);
|
||||||
|
static AsmOp BoolConst(bool f);
|
||||||
static AsmOp Const(std::string push_op) {
|
static AsmOp Const(std::string push_op) {
|
||||||
return AsmOp(a_const, 0, 1, std::move(push_op));
|
return AsmOp(a_const, 0, 1, std::move(push_op));
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,8 +101,12 @@ dictnew constant special-dict
|
||||||
1 'nop
|
1 'nop
|
||||||
} ::_ sg~
|
} ::_ sg~
|
||||||
|
|
||||||
// gas_price gas_limit spec_limit gas_credit block_gas_limit freeze_due_limit delete_due_limit -- c
|
// gas_price gas_limit spec_limit gas_credit block_gas_limit freeze_due_limit delete_due_limit b -- c
|
||||||
{ 7 0 reverse <b x{de} s, { swap 64 u, } 7 times b>
|
{ 7 1 reverse x{de} s, { swap 64 u, } 7 times b>
|
||||||
|
} : make-gas-prices-basic
|
||||||
|
// gas_price ... delete_due_limit flat_gas_limit flat_gas_rate -- c
|
||||||
|
{ 2dup or { <b x{d1} s, rot 64 u, swap 64 u, } { 2drop <b } cond
|
||||||
|
make-gas-prices-basic
|
||||||
} : make-gas-prices
|
} : make-gas-prices
|
||||||
{ make-gas-prices 20 config! } : config.mc_gas_prices!
|
{ make-gas-prices 20 config! } : config.mc_gas_prices!
|
||||||
{ make-gas-prices 21 config! } : config.gas_prices!
|
{ make-gas-prices 21 config! } : config.gas_prices!
|
||||||
|
|
|
@ -171,9 +171,9 @@ elector_addr config.elector_smc!
|
||||||
1 500 1000 500000 config.storage_prices!
|
1 500 1000 500000 config.storage_prices!
|
||||||
config.special!
|
config.special!
|
||||||
|
|
||||||
// gas_price gas_limit special_gas_limit gas_credit block_gas_limit freeze_due_limit delete_due_limit --
|
// gas_price gas_limit special_gas_limit gas_credit block_gas_limit freeze_due_limit delete_due_limit flat_gas_limit flat_gas_price --
|
||||||
1000 sg* 1 *M dup 10000 10 *M GR$0.1 GR$1.0 config.gas_prices!
|
1000 sg* 1 *M dup 10000 10 *M GR$0.1 GR$1.0 100 100000 config.gas_prices!
|
||||||
10000 sg* 1 *M 10 *M 10000 10 *M GR$0.1 GR$1.0 config.mc_gas_prices!
|
10000 sg* 1 *M 10 *M 10000 10 *M GR$0.1 GR$1.0 0 0 config.mc_gas_prices!
|
||||||
// lump_price bit_price cell_price ihr_factor first_frac next_frac
|
// lump_price bit_price cell_price ihr_factor first_frac next_frac
|
||||||
1000000 1000 sg* 100000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.fwd_prices!
|
1000000 1000 sg* 100000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.fwd_prices!
|
||||||
10000000 10000 sg* 1000000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.mc_fwd_prices!
|
10000000 10000 sg* 1000000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.mc_fwd_prices!
|
||||||
|
|
|
@ -745,6 +745,26 @@ Ref<Cell> CellSlice::fetch_ref() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CellSlice::prefetch_maybe_ref(Ref<vm::Cell>& res) const {
|
||||||
|
auto z = prefetch_ulong(1);
|
||||||
|
if (!z) {
|
||||||
|
res.clear();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return z == 1 && prefetch_ref_to(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CellSlice::fetch_maybe_ref(Ref<vm::Cell>& res) {
|
||||||
|
auto z = prefetch_ulong(1);
|
||||||
|
if (!z) {
|
||||||
|
res.clear();
|
||||||
|
return advance(1);
|
||||||
|
} else {
|
||||||
|
return z == 1 && prefetch_ref_to(res) && advance_ext(1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CellSlice::begins_with(unsigned bits, unsigned long long value) const {
|
bool CellSlice::begins_with(unsigned bits, unsigned long long value) const {
|
||||||
return have(bits) && !((prefetch_ulong(bits) ^ value) & ((1ULL << bits) - 1));
|
return have(bits) && !((prefetch_ulong(bits) ^ value) & ((1ULL << bits) - 1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,8 @@ class CellSlice : public td::CntObject {
|
||||||
bool prefetch_ref_to(Ref<Cell>& ref, unsigned offset = 0) const {
|
bool prefetch_ref_to(Ref<Cell>& ref, unsigned offset = 0) const {
|
||||||
return (ref = prefetch_ref(offset)).not_null();
|
return (ref = prefetch_ref(offset)).not_null();
|
||||||
}
|
}
|
||||||
|
bool fetch_maybe_ref(Ref<Cell>& ref);
|
||||||
|
bool prefetch_maybe_ref(Ref<Cell>& ref) const;
|
||||||
td::BitSlice fetch_bits(unsigned bits);
|
td::BitSlice fetch_bits(unsigned bits);
|
||||||
td::BitSlice prefetch_bits(unsigned bits) const;
|
td::BitSlice prefetch_bits(unsigned bits) const;
|
||||||
td::Ref<CellSlice> fetch_subslice(unsigned bits, unsigned refs = 0);
|
td::Ref<CellSlice> fetch_subslice(unsigned bits, unsigned refs = 0);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
The aim of this document is to provide step-by-step instructions for setting up a full node for the TON Blockchain. We assume some familiarity with the TON Blockchain Lite Client, at least to the extent explained in the Lite Client HOWTO.
|
The aim of this document is to provide step-by-step instructions for setting up a full node for the TON Blockchain. We assume some familiarity with the TON Blockchain Lite Client, at least to the extent explained in the Lite Client HOWTO.
|
||||||
|
|
||||||
Notice that you need a machine with a public IP address and a high-bandwidth network connection to run a TON Blockchain Full Node. Typically you'll need a sufficiently powerful server in a datacenter. It is a bad idea to run a Full Node on your home computer; instead, you could run a Full Node on a remote server, and use the TON Blockchain Lite Client to connect to it from home.
|
Note that you need a machine with a public IP address and a high-bandwidth network connection to run a TON Blockchain Full Node. Typically you'll need a sufficiently powerful server in a datacenter with good network connectivity, using at least a 1 Gbit/s connection to reliably accommodate peak loads (the average load is expected to be approximately 100 Mbit/s). We recommend a dual-processor server with at least eight cores in each processor, at least 256 MiB RAM, at least 8 TB of conventional HDD storage and at least 512 GB of faster SSD storage. It is a bad idea to run a Full Node on your home computer; instead, you could run a Full Node on a remote server, and use the TON Blockchain Lite Client to connect to it from home.
|
||||||
|
|
||||||
0. Downloading and compiling
|
0. Downloading and compiling
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
The aim of this document is to provide step-by-step instructions for setting up a full node for the TON Blockchain as a validator. We assume that a TON Blockchain Full Node is already up and running as explained in FullNode-HOWTO. We also assume some familiarity with the TON Blockchain Lite Client.
|
The aim of this document is to provide step-by-step instructions for setting up a full node for the TON Blockchain as a validator. We assume that a TON Blockchain Full Node is already up and running as explained in FullNode-HOWTO. We also assume some familiarity with the TON Blockchain Lite Client.
|
||||||
|
|
||||||
Notice that a validator must be run on a dedicated high-performance server with high network bandwidth installed in a reliable datacenter, and that you'll need a large amount of Grams (test Grams, if you want to run a validator in the "testnet") as stakes for your validator. If your validator works incorrectly or is not available for prolonged periods of time, you may lose part or all of your stake, so it makes sense to use high-performance, reliable servers.
|
Note that a validator must be run on a dedicated high-performance server with high network bandwidth installed in a reliable datacenter, and that you'll need a large amount of Grams (test Grams, if you want to run a validator in the "testnet") as stakes for your validator. If your validator works incorrectly or is not available for prolonged periods of time, you may lose part or all of your stake, so it makes sense to use high-performance, reliable servers. We recommend a dual-processor server with at least eight cores in each processor, at least 256 MiB RAM, at least 8 TB of conventional HDD storage and at least 512 GB of faster SSD storage, with 1 Gbit/s network (and Internet) connectivity to reliably accomodate peak loads.
|
||||||
|
|
||||||
0. Downloading and compiling
|
0. Downloading and compiling
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -12,9 +12,9 @@ The basic instructions are the same as for a TON Blockchain Full Node, as explai
|
||||||
|
|
||||||
In order to run a Validator, you'll need a Full Node that is already up and running (and completely synchronized with the current blockchain state), and a wallet in the masterchain holding a large amount of Grams (or test Grams, if you want to run a validator in the "testnet" TON Blockchain instance). Typically you'll need at least 100,000 Grams.
|
In order to run a Validator, you'll need a Full Node that is already up and running (and completely synchronized with the current blockchain state), and a wallet in the masterchain holding a large amount of Grams (or test Grams, if you want to run a validator in the "testnet" TON Blockchain instance). Typically you'll need at least 100,000 Grams.
|
||||||
|
|
||||||
Each validator is identified by its (Ed25519) public key. During the validator elections, the validator (or rather its public key) is also associated with a smart contract residing in the masterchain. For simplicity, we say that the validator is "controlled" by this smart contract (e.g., a wallet smart contract). Stakes are accepted on behalf of this validator only if they arrive from its associated smart contract, and only that associated smart contract is entitled to collect the validator's stake after it is unfrozen, along with the validator's share of bonuses (e.g., block mining fees, transaction and message forwarding fees collected from the users of the TON Blockchain by the validator pool). Typically the bonuses are distributed proportionally to the (effective) stakes of the validators. On the other hand, validators with higher stakes are assigned a larger amount of work to perform (i.e., they have to create and validate blocks for more shardchains), so it is important not to get too greedy.
|
Each validator is identified by its (Ed25519) public key. During the validator elections, the validator (or rather its public key) is also associated with a smart contract residing in the masterchain. For simplicity, we say that the validator is "controlled" by this smart contract (e.g., a wallet smart contract). Stakes are accepted on behalf of this validator only if they arrive from its associated smart contract, and only that associated smart contract is entitled to collect the validator's stake after it is unfrozen, along with the validator's share of bonuses (e.g., block mining fees, transaction and message forwarding fees collected from the users of the TON Blockchain by the validator pool). Typically the bonuses are distributed proportionally to the (effective) stakes of the validators. On the other hand, validators with higher stakes are assigned a larger amount of work to perform (i.e., they have to create and validate blocks for more shardchains), so it is important not to stake an amount that will yield more validation work than your node is capable of handling.
|
||||||
|
|
||||||
Notice that each validator (identified by its public key) can be associated with at most one controlling smart contract (residing in the masterchain), but the same controlling smart contract may be associated with several validators. In this way you can run several validators (on different physical servers) and make stakes for them from the same smart contract. If one of these validators breaks down and you lose its stake, at least the other validators will continue working and will keep their stakes and receive bonuses.
|
Notice that each validator (identified by its public key) can be associated with at most one controlling smart contract (residing in the masterchain), but the same controlling smart contract may be associated with several validators. In this way you can run several validators (on different physical servers) and make stakes for them from the same smart contract. If one of these validators stops functioning and you lose its stake, the other validators should continue operating and will keep their stakes and potentially receive bonuses.
|
||||||
|
|
||||||
2. Creating the controlling smart contract
|
2. Creating the controlling smart contract
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -231,4 +231,4 @@ If you have done everything correctly (in particular indicated the correct seqno
|
||||||
7. Participating in the next elections
|
7. Participating in the next elections
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Notice that even before the term of the validator group containing your elected validator finishes, new elections for the next validator group will be announced. You'll probably want to participate in them as well. For this, you can use the same validator, but you must generate a new validator key and new ADNL address. You'll also have to make a new stake before your previous stake is returned (because your previous stake will be unfrozen and returned only some time after the next validator group becomes active), so it does not make sense to stake more than half of your Grams.
|
Notice that even before the term of the validator group containing your elected validator finishes, new elections for the next validator group will be announced. You'll probably want to participate in them as well. For this, you can use the same validator, but you must generate a new validator key and new ADNL address. You'll also have to make a new stake before your previous stake is returned (because your previous stake will be unfrozen and returned only some time after the next validator group becomes active), so if you want to participate in concurrent elections, it likely does not make sense to stake more than half of your Grams.
|
||||||
|
|
|
@ -364,7 +364,7 @@ inline void register_actor_info_ptr(core::ActorInfoPtr actor_info_ptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class... ArgsT>
|
template <class T, class... ArgsT>
|
||||||
core::ActorInfoPtr create_actor(core::ActorOptions &options, ArgsT &&... args) {
|
core::ActorInfoPtr create_actor(core::ActorOptions &options, ArgsT &&... args) noexcept {
|
||||||
auto *scheduler_context = core::SchedulerContext::get();
|
auto *scheduler_context = core::SchedulerContext::get();
|
||||||
if (!options.has_scheduler()) {
|
if (!options.has_scheduler()) {
|
||||||
options.on_scheduler(scheduler_context->get_scheduler_id());
|
options.on_scheduler(scheduler_context->get_scheduler_id());
|
||||||
|
|
|
@ -75,7 +75,7 @@ void ActorExecutor::send(ActorSignals signals) {
|
||||||
pending_signals_.add_signals(signals);
|
pending_signals_.add_signals(signals);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActorExecutor::start() {
|
void ActorExecutor::start() noexcept {
|
||||||
//LOG(ERROR) << "START " << actor_info_.get_name() << " " << tag("from_queue", options.from_queue);
|
//LOG(ERROR) << "START " << actor_info_.get_name() << " " << tag("from_queue", options.from_queue);
|
||||||
if (is_closed()) {
|
if (is_closed()) {
|
||||||
return;
|
return;
|
||||||
|
@ -126,7 +126,7 @@ void ActorExecutor::start() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActorExecutor::finish() {
|
void ActorExecutor::finish() noexcept {
|
||||||
//LOG(ERROR) << "FINISH " << actor_info_.get_name() << " " << tag("own_lock", actor_locker_.own_lock());
|
//LOG(ERROR) << "FINISH " << actor_info_.get_name() << " " << tag("own_lock", actor_locker_.own_lock());
|
||||||
if (!actor_locker_.own_lock()) {
|
if (!actor_locker_.own_lock()) {
|
||||||
if (!pending_signals_.empty() && actor_locker_.add_signals(pending_signals_)) {
|
if (!pending_signals_.empty() && actor_locker_.add_signals(pending_signals_)) {
|
||||||
|
|
|
@ -106,8 +106,8 @@ class ActorExecutor {
|
||||||
return flags_;
|
return flags_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start();
|
void start() noexcept;
|
||||||
void finish();
|
void finish() noexcept;
|
||||||
|
|
||||||
bool flush_one(ActorSignals &signals);
|
bool flush_one(ActorSignals &signals);
|
||||||
bool flush_one_signal(ActorSignals &signals);
|
bool flush_one_signal(ActorSignals &signals);
|
||||||
|
|
|
@ -50,6 +50,9 @@
|
||||||
|
|
||||||
#define TRY_RESULT(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result)
|
#define TRY_RESULT(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result)
|
||||||
|
|
||||||
|
#define TRY_RESULT_PROMISE(promise_name, name, result) \
|
||||||
|
TRY_RESULT_PROMISE_IMPL(promise_name, TD_CONCAT(TD_CONCAT(r_, name), __LINE__), auto name, result)
|
||||||
|
|
||||||
#define TRY_RESULT_ASSIGN(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), name, result)
|
#define TRY_RESULT_ASSIGN(name, result) TRY_RESULT_IMPL(TD_CONCAT(TD_CONCAT(r_, name), __LINE__), name, result)
|
||||||
|
|
||||||
#define TRY_RESULT_PREFIX(name, result, prefix) \
|
#define TRY_RESULT_PREFIX(name, result, prefix) \
|
||||||
|
@ -78,10 +81,18 @@
|
||||||
} \
|
} \
|
||||||
name = r_name.move_as_ok();
|
name = r_name.move_as_ok();
|
||||||
|
|
||||||
|
#define TRY_RESULT_PROMISE_IMPL(promise_name, r_name, name, result) \
|
||||||
|
auto r_name = (result); \
|
||||||
|
if (r_name.is_error()) { \
|
||||||
|
promise_name.set_error(r_name.move_as_error()); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
name = r_name.move_as_ok();
|
||||||
|
|
||||||
#define TRY_RESULT_PROMISE_PREFIX_IMPL(promise_name, r_name, name, result, prefix) \
|
#define TRY_RESULT_PROMISE_PREFIX_IMPL(promise_name, r_name, name, result, prefix) \
|
||||||
auto r_name = (result); \
|
auto r_name = (result); \
|
||||||
if (r_name.is_error()) { \
|
if (r_name.is_error()) { \
|
||||||
promise.set_error(r_name.move_as_error()); \
|
promise_name.set_error(r_name.move_as_error_prefix(prefix)); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
name = r_name.move_as_ok();
|
name = r_name.move_as_ok();
|
||||||
|
@ -298,14 +309,31 @@ class Status {
|
||||||
return std::move(*this);
|
return std::move(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status move_as_error_prefix(Slice prefix) TD_WARN_UNUSED_RESULT {
|
Status move_as_error_prefix(const Status &status) const TD_WARN_UNUSED_RESULT {
|
||||||
|
return status.move_as_error_suffix(message());
|
||||||
|
}
|
||||||
|
|
||||||
|
Status move_as_error_prefix(Slice prefix) const TD_WARN_UNUSED_RESULT {
|
||||||
CHECK(is_error());
|
CHECK(is_error());
|
||||||
Info info = get_info();
|
Info info = get_info();
|
||||||
switch (info.error_type) {
|
switch (info.error_type) {
|
||||||
case ErrorType::general:
|
case ErrorType::general:
|
||||||
return Error(code(), PSLICE() << prefix << message());
|
return Error(code(), PSLICE() << prefix << " " << message());
|
||||||
case ErrorType::os:
|
case ErrorType::os:
|
||||||
return Status(false, ErrorType::os, code(), PSLICE() << prefix << message());
|
return Status(false, ErrorType::os, code(), PSLICE() << prefix << " " << message());
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Status move_as_error_suffix(Slice suffix) const TD_WARN_UNUSED_RESULT {
|
||||||
|
CHECK(is_error());
|
||||||
|
Info info = get_info();
|
||||||
|
switch (info.error_type) {
|
||||||
|
case ErrorType::general:
|
||||||
|
return Error(code(), PSLICE() << message() << " " << suffix);
|
||||||
|
case ErrorType::os:
|
||||||
|
return Status(false, ErrorType::os, code(), PSLICE() << message() << " " << suffix);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return {};
|
return {};
|
||||||
|
@ -488,6 +516,18 @@ class Result {
|
||||||
};
|
};
|
||||||
return status_.move_as_error_prefix(prefix);
|
return status_.move_as_error_prefix(prefix);
|
||||||
}
|
}
|
||||||
|
Status move_as_error_prefix(const Status &prefix) TD_WARN_UNUSED_RESULT {
|
||||||
|
SCOPE_EXIT {
|
||||||
|
status_ = Status::Error<-5>();
|
||||||
|
};
|
||||||
|
return status_.move_as_error_prefix(prefix);
|
||||||
|
}
|
||||||
|
Status move_as_error_suffix(Slice suffix) TD_WARN_UNUSED_RESULT {
|
||||||
|
SCOPE_EXIT {
|
||||||
|
status_ = Status::Error<-5>();
|
||||||
|
};
|
||||||
|
return status_.move_as_error_suffix(suffix);
|
||||||
|
}
|
||||||
const T &ok() const {
|
const T &ok() const {
|
||||||
LOG_CHECK(status_.is_ok()) << status_;
|
LOG_CHECK(status_.is_ok()) << status_;
|
||||||
return value_;
|
return value_;
|
||||||
|
|
|
@ -32,10 +32,10 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#define BEGIN_STORE_FLAGS() \
|
#define BEGIN_STORE_FLAGS() \
|
||||||
do { \
|
do { \
|
||||||
uint32 flags_store = 0; \
|
td::uint32 flags_store = 0; \
|
||||||
uint32 bit_offset_store = 0
|
td::uint32 bit_offset_store = 0
|
||||||
|
|
||||||
#define STORE_FLAG(flag) \
|
#define STORE_FLAG(flag) \
|
||||||
flags_store |= (flag) << bit_offset_store; \
|
flags_store |= (flag) << bit_offset_store; \
|
||||||
|
@ -47,10 +47,10 @@
|
||||||
} \
|
} \
|
||||||
while (false)
|
while (false)
|
||||||
|
|
||||||
#define BEGIN_PARSE_FLAGS() \
|
#define BEGIN_PARSE_FLAGS() \
|
||||||
do { \
|
do { \
|
||||||
uint32 flags_parse; \
|
td::uint32 flags_parse; \
|
||||||
uint32 bit_offset_parse = 0; \
|
td::uint32 bit_offset_parse = 0; \
|
||||||
td::parse(flags_parse, parser)
|
td::parse(flags_parse, parser)
|
||||||
|
|
||||||
#define PARSE_FLAG(flag) \
|
#define PARSE_FLAG(flag) \
|
||||||
|
|
|
@ -99,6 +99,16 @@ class TlParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool can_prefetch_int() const {
|
||||||
|
return get_left_len() >= sizeof(int32);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 prefetch_int_unsafe() const {
|
||||||
|
int32 result;
|
||||||
|
std::memcpy(&result, data, sizeof(int32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int32 fetch_int_unsafe() {
|
int32 fetch_int_unsafe() {
|
||||||
int32 result;
|
int32 result;
|
||||||
std::memcpy(&result, data, sizeof(int32));
|
std::memcpy(&result, data, sizeof(int32));
|
||||||
|
|
|
@ -74,3 +74,4 @@ liteServer.getConfigParams mode:# id:tonNode.blockIdExt param_list:(vector int)
|
||||||
|
|
||||||
liteServer.queryPrefix = Object;
|
liteServer.queryPrefix = Object;
|
||||||
liteServer.query data:bytes = Object;
|
liteServer.query data:bytes = Object;
|
||||||
|
liteServer.waitMasterchainSeqno seqno:int timeout_ms:int = Object; // query prefix
|
||||||
|
|
Binary file not shown.
|
@ -444,12 +444,14 @@ db.state.initBlockId block:tonNode.blockIdExt = db.state.InitBlockId;
|
||||||
db.state.gcBlockId block:tonNode.blockIdExt = db.state.GcBlockId;
|
db.state.gcBlockId block:tonNode.blockIdExt = db.state.GcBlockId;
|
||||||
db.state.shardClient block:tonNode.blockIdExt = db.state.ShardClient;
|
db.state.shardClient block:tonNode.blockIdExt = db.state.ShardClient;
|
||||||
db.state.asyncSerializer block:tonNode.blockIdExt last:tonNode.blockIdExt last_ts:int = db.state.AsyncSerializer;
|
db.state.asyncSerializer block:tonNode.blockIdExt last:tonNode.blockIdExt last_ts:int = db.state.AsyncSerializer;
|
||||||
|
db.state.hardforks blocks:(vector tonNode.blockIdExt) = db.state.Hardforks;
|
||||||
|
|
||||||
db.state.key.destroyedSessions = db.state.Key;
|
db.state.key.destroyedSessions = db.state.Key;
|
||||||
db.state.key.initBlockId = db.state.Key;
|
db.state.key.initBlockId = db.state.Key;
|
||||||
db.state.key.gcBlockId = db.state.Key;
|
db.state.key.gcBlockId = db.state.Key;
|
||||||
db.state.key.shardClient = db.state.Key;
|
db.state.key.shardClient = db.state.Key;
|
||||||
db.state.key.asyncSerializer = db.state.Key;
|
db.state.key.asyncSerializer = db.state.Key;
|
||||||
|
db.state.key.hardforks = db.state.Key;
|
||||||
|
|
||||||
db.lt.el.key workchain:int shard:long idx:int = db.lt.Key;
|
db.lt.el.key workchain:int shard:long idx:int = db.lt.Key;
|
||||||
db.lt.desc.key workchain:int shard:long = db.lt.Key;
|
db.lt.desc.key workchain:int shard:long = db.lt.Key;
|
||||||
|
|
Binary file not shown.
|
@ -39,8 +39,8 @@ internal.transactionId lt:int64 hash:bytes = internal.TransactionId;
|
||||||
|
|
||||||
raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState;
|
raw.initialAccountState code:bytes data:bytes = raw.InitialAccountState;
|
||||||
raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState;
|
raw.accountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId sync_utime:int53 = raw.AccountState;
|
||||||
raw.message source:string destination:string value:int64 message:bytes = raw.Message;
|
raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes message:bytes = raw.Message;
|
||||||
raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
|
raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
|
||||||
raw.transactions transactions:vector<raw.transaction> previous_transaction_id:internal.transactionId = raw.Transactions;
|
raw.transactions transactions:vector<raw.transaction> previous_transaction_id:internal.transactionId = raw.Transactions;
|
||||||
|
|
||||||
testWallet.initialAccountState public_key:string = testWallet.InitialAccountState;
|
testWallet.initialAccountState public_key:string = testWallet.InitialAccountState;
|
||||||
|
@ -63,7 +63,7 @@ generic.accountStateWallet account_state:wallet.accountState = generic.AccountSt
|
||||||
generic.accountStateTestGiver account_state:testGiver.accountState = generic.AccountState;
|
generic.accountStateTestGiver account_state:testGiver.accountState = generic.AccountState;
|
||||||
generic.accountStateUninited account_state:uninited.accountState = generic.AccountState;
|
generic.accountStateUninited account_state:uninited.accountState = generic.AccountState;
|
||||||
|
|
||||||
sendGramsResult sent_until:int53 = SendGramsResult;
|
sendGramsResult sent_until:int53 body_hash:bytes = SendGramsResult;
|
||||||
|
|
||||||
updateSendLiteServerQuery id:int64 data:bytes = Update;
|
updateSendLiteServerQuery id:int64 data:bytes = Update;
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ options.setConfig config:config = Ok;
|
||||||
|
|
||||||
createNewKey local_password:secureBytes mnemonic_password:secureBytes random_extra_seed:secureBytes = Key;
|
createNewKey local_password:secureBytes mnemonic_password:secureBytes random_extra_seed:secureBytes = Key;
|
||||||
deleteKey key:key = Ok;
|
deleteKey key:key = Ok;
|
||||||
|
deleteAllKeys = Ok;
|
||||||
exportKey input_key:inputKey = ExportedKey;
|
exportKey input_key:inputKey = ExportedKey;
|
||||||
exportPemKey input_key:inputKey key_password:secureBytes = ExportedPemKey;
|
exportPemKey input_key:inputKey key_password:secureBytes = ExportedPemKey;
|
||||||
exportEncryptedKey input_key:inputKey key_password:secureBytes = ExportedEncryptedKey;
|
exportEncryptedKey input_key:inputKey key_password:secureBytes = ExportedEncryptedKey;
|
||||||
|
|
Binary file not shown.
|
@ -68,7 +68,7 @@ int TD_TL_writer::get_storer_type(const tl::tl_combinator *t, const std::string
|
||||||
|
|
||||||
tl::TL_writer::Mode TD_TL_writer::get_parser_mode(int type) const {
|
tl::TL_writer::Mode TD_TL_writer::get_parser_mode(int type) const {
|
||||||
if (tl_name == "tonlib_api") {
|
if (tl_name == "tonlib_api") {
|
||||||
#ifndef TD_ENABLE_JNI // we need to parse all types in order to implement toString
|
#ifndef TONLIB_ENABLE_JNI // we need to parse all types in order to implement toString
|
||||||
return Server;
|
return Server;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ add_executable(tonlib-cli tonlib/tonlib-cli.cpp)
|
||||||
target_link_libraries(tonlib-cli tonlib tdactor tdutils terminal)
|
target_link_libraries(tonlib-cli tonlib tdactor tdutils terminal)
|
||||||
|
|
||||||
if (NOT CMAKE_CROSSCOMPILING)
|
if (NOT CMAKE_CROSSCOMPILING)
|
||||||
if (TD_ENABLE_JNI)
|
if (TONLIB_ENABLE_JNI)
|
||||||
#FIXME
|
#FIXME
|
||||||
#add_dependencies(tonlib tonlib_generate_java_api)
|
#add_dependencies(tonlib tonlib_generate_java_api)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -420,9 +420,14 @@ TEST(Tonlib, ParseAddres) {
|
||||||
ASSERT_EQ(-1, addr->workchain_id_);
|
ASSERT_EQ(-1, addr->workchain_id_);
|
||||||
ASSERT_EQ(true, addr->bounceable_);
|
ASSERT_EQ(true, addr->bounceable_);
|
||||||
ASSERT_EQ(false, addr->testnet_);
|
ASSERT_EQ(false, addr->testnet_);
|
||||||
|
auto raw = addr->addr_;
|
||||||
|
|
||||||
auto addr_str = sync_send(client, make_object<tonlib_api::packAccountAddress>(std::move(addr))).move_as_ok();
|
auto addr_str = sync_send(client, make_object<tonlib_api::packAccountAddress>(std::move(addr))).move_as_ok();
|
||||||
ASSERT_EQ("Ef9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfYFX", addr_str->account_address_);
|
ASSERT_EQ("Ef9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfYFX", addr_str->account_address_);
|
||||||
|
auto addr_str2 = sync_send(client, make_object<tonlib_api::packAccountAddress>(
|
||||||
|
make_object<tonlib_api::unpackedAccountAddress>(-1, false, false, raw)))
|
||||||
|
.move_as_ok();
|
||||||
|
ASSERT_EQ("Uf9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfdyS", addr_str2->account_address_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Tonlib, KeysApi) {
|
TEST(Tonlib, KeysApi) {
|
||||||
|
@ -550,7 +555,7 @@ TEST(Tonlib, KeysApi) {
|
||||||
make_object<tonlib_api::inputKey>(
|
make_object<tonlib_api::inputKey>(
|
||||||
make_object<tonlib_api::key>(key->public_key_, imported_key->secret_.copy()), new_local_password.copy()),
|
make_object<tonlib_api::key>(key->public_key_, imported_key->secret_.copy()), new_local_password.copy()),
|
||||||
pem_password.copy()));
|
pem_password.copy()));
|
||||||
if (r_exported_pem_key.is_error() && r_exported_pem_key.error().message() == "Not supported") {
|
if (r_exported_pem_key.is_error() && r_exported_pem_key.error().message() == "INTERNAL Not supported") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto exported_pem_key = r_exported_pem_key.move_as_ok();
|
auto exported_pem_key = r_exported_pem_key.move_as_ok();
|
||||||
|
|
|
@ -30,7 +30,7 @@ void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
if (client_.last_block_actor_.empty()) {
|
if (client_.last_block_actor_.empty()) {
|
||||||
return P.set_error(td::Status::Error(500, "No lite clients"));
|
return P.set_error(TonlibError::NoLiteServers());
|
||||||
}
|
}
|
||||||
td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
|
td::actor::send_closure(client_.last_block_actor_, &LastBlock::get_last_block, std::move(P));
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ void ExtClient::send_raw_query(td::BufferSlice query, td::Promise<td::BufferSlic
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
if (client_.andl_ext_client_.empty()) {
|
if (client_.andl_ext_client_.empty()) {
|
||||||
return P.set_error(td::Status::Error(500, "No lite clients"));
|
return P.set_error(TonlibError::NoLiteServers());
|
||||||
}
|
}
|
||||||
td::actor::send_closure(client_.andl_ext_client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(query),
|
td::actor::send_closure(client_.andl_ext_client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(query),
|
||||||
td::Timestamp::in(10.0), std::move(P));
|
td::Timestamp::in(10.0), std::move(P));
|
||||||
|
|
|
@ -26,6 +26,10 @@
|
||||||
|
|
||||||
#include "td/actor/actor.h"
|
#include "td/actor/actor.h"
|
||||||
#include "td/utils/Container.h"
|
#include "td/utils/Container.h"
|
||||||
|
#include "td/utils/Random.h"
|
||||||
|
|
||||||
|
#include "TonlibError.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
class LastBlock;
|
class LastBlock;
|
||||||
|
@ -53,23 +57,37 @@ class ExtClient {
|
||||||
void with_last_block(td::Promise<LastBlockState> promise);
|
void with_last_block(td::Promise<LastBlockState> promise);
|
||||||
|
|
||||||
template <class QueryT>
|
template <class QueryT>
|
||||||
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise) {
|
void send_query(QueryT query, td::Promise<typename QueryT::ReturnType> promise, td::int32 seq_no = -1) {
|
||||||
auto raw_query = ton::serialize_tl_object(&query, true);
|
auto raw_query = ton::serialize_tl_object(&query, true);
|
||||||
LOG(ERROR) << "send query to liteserver: " << to_string(query);
|
td::uint32 tag = td::Random::fast_uint32();
|
||||||
|
VLOG(lite_server) << "send query to liteserver: " << tag << " " << to_string(query);
|
||||||
td::BufferSlice liteserver_query =
|
td::BufferSlice liteserver_query =
|
||||||
ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
|
ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_query>(std::move(raw_query)), true);
|
||||||
|
|
||||||
send_raw_query(std::move(liteserver_query), [promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
|
if (seq_no >= 0) {
|
||||||
promise.set_result([&]() -> td::Result<typename QueryT::ReturnType> {
|
auto wait = ton::lite_api::liteServer_waitMasterchainSeqno(seq_no, 5000);
|
||||||
TRY_RESULT(data, std::move(R));
|
VLOG(lite_server) << " with prefix " << to_string(wait);
|
||||||
auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
|
auto prefix = ton::serialize_tl_object(&wait, true);
|
||||||
if (r_error.is_ok()) {
|
liteserver_query = td::BufferSlice(PSLICE() << prefix.as_slice() << liteserver_query.as_slice());
|
||||||
auto f = r_error.move_as_ok();
|
}
|
||||||
return td::Status::Error(f->code_, f->message_);
|
|
||||||
}
|
send_raw_query(
|
||||||
return ton::fetch_result<QueryT>(std::move(data));
|
std::move(liteserver_query), [promise = std::move(promise), tag](td::Result<td::BufferSlice> R) mutable {
|
||||||
}());
|
auto res = [&]() -> td::Result<typename QueryT::ReturnType> {
|
||||||
});
|
TRY_RESULT_PREFIX(data, std::move(R), TonlibError::LiteServerNetwork());
|
||||||
|
auto r_error = ton::fetch_tl_object<ton::lite_api::liteServer_error>(data.clone(), true);
|
||||||
|
if (r_error.is_ok()) {
|
||||||
|
auto f = r_error.move_as_ok();
|
||||||
|
return TonlibError::LiteServer(f->code_, f->message_);
|
||||||
|
}
|
||||||
|
return ton::fetch_result<QueryT>(std::move(data));
|
||||||
|
}
|
||||||
|
();
|
||||||
|
VLOG_IF(lite_server, res.is_ok())
|
||||||
|
<< "got result from liteserver: " << tag << " " << td::Slice(to_string(res.ok())).truncate(1 << 12);
|
||||||
|
VLOG_IF(lite_server, res.is_error()) << "got error from liteserver: " << tag << " " << res.error();
|
||||||
|
promise.set_result(std::move(res));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
Copyright 2017-2019 Telegram Systems LLP
|
Copyright 2017-2019 Telegram Systems LLP
|
||||||
*/
|
*/
|
||||||
#include "ExtClientOutbound.h"
|
#include "ExtClientOutbound.h"
|
||||||
|
#include "TonlibError.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ class ExtClientOutboundImp : public ExtClientOutbound {
|
||||||
void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {
|
void on_query_result(td::int64 id, td::Result<td::BufferSlice> r_data, td::Promise<td::Unit> promise) override {
|
||||||
auto it = queries_.find(id);
|
auto it = queries_.find(id);
|
||||||
if (it == queries_.end()) {
|
if (it == queries_.end()) {
|
||||||
promise.set_error(td::Status::Error(400, "Unknown query id"));
|
promise.set_error(TonlibError::Internal("Unknown query id"));
|
||||||
}
|
}
|
||||||
it->second.set_result(std::move(r_data));
|
it->second.set_result(std::move(r_data));
|
||||||
queries_.erase(it);
|
queries_.erase(it);
|
||||||
|
@ -54,7 +55,7 @@ class ExtClientOutboundImp : public ExtClientOutbound {
|
||||||
|
|
||||||
void tear_down() override {
|
void tear_down() override {
|
||||||
for (auto &it : queries_) {
|
for (auto &it : queries_) {
|
||||||
it.second.set_error(td::Status::Error(400, "Query cancelled"));
|
it.second.set_error(TonlibError::Cancelled());
|
||||||
}
|
}
|
||||||
queries_.clear();
|
queries_.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,19 @@
|
||||||
#include "tonlib/utils.h"
|
#include "tonlib/utils.h"
|
||||||
#include "block/block-auto.h"
|
#include "block/block-auto.h"
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) {
|
td::Ref<vm::Cell> GenericAccount::get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept {
|
||||||
return vm::CellBuilder()
|
return vm::CellBuilder()
|
||||||
.append_cellslice(binary_bitstring_to_cellslice("b{00110}").move_as_ok())
|
.append_cellslice(binary_bitstring_to_cellslice("b{00110}").move_as_ok())
|
||||||
.store_ref(std::move(code))
|
.store_ref(std::move(code))
|
||||||
.store_ref(std::move(data))
|
.store_ref(std::move(data))
|
||||||
.finalize();
|
.finalize();
|
||||||
}
|
}
|
||||||
block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state) {
|
block::StdAddress GenericAccount::get_address(ton::WorkchainId workchain_id,
|
||||||
|
const td::Ref<vm::Cell>& init_state) noexcept {
|
||||||
return block::StdAddress(workchain_id, init_state->get_hash().bits(), true /*bounce*/);
|
return block::StdAddress(workchain_id, init_state->get_hash().bits(), true /*bounce*/);
|
||||||
}
|
}
|
||||||
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
td::Ref<vm::Cell> GenericAccount::create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||||
td::Ref<vm::Cell> body) {
|
td::Ref<vm::Cell> body) noexcept {
|
||||||
block::gen::Message::Record message;
|
block::gen::Message::Record message;
|
||||||
/*info*/ {
|
/*info*/ {
|
||||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
class GenericAccount {
|
class GenericAccount {
|
||||||
public:
|
public:
|
||||||
static td::Ref<vm::Cell> get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data);
|
static td::Ref<vm::Cell> get_init_state(td::Ref<vm::Cell> code, td::Ref<vm::Cell> data) noexcept;
|
||||||
static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state);
|
static block::StdAddress get_address(ton::WorkchainId workchain_id, const td::Ref<vm::Cell>& init_state) noexcept;
|
||||||
static td::Ref<vm::Cell> create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
static td::Ref<vm::Cell> create_ext_message(const block::StdAddress& address, td::Ref<vm::Cell> new_state,
|
||||||
td::Ref<vm::Cell> body);
|
td::Ref<vm::Cell> body) noexcept;
|
||||||
};
|
};
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|
|
@ -22,9 +22,12 @@
|
||||||
#include "tonlib/keys/DecryptedKey.h"
|
#include "tonlib/keys/DecryptedKey.h"
|
||||||
#include "tonlib/keys/EncryptedKey.h"
|
#include "tonlib/keys/EncryptedKey.h"
|
||||||
|
|
||||||
|
#include "tonlib/TonlibError.h"
|
||||||
|
|
||||||
#include "td/utils/filesystem.h"
|
#include "td/utils/filesystem.h"
|
||||||
#include "td/utils/port/path.h"
|
#include "td/utils/port/path.h"
|
||||||
#include "td/utils/crypto.h"
|
#include "td/utils/crypto.h"
|
||||||
|
#include "td/utils/PathView.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -47,7 +50,7 @@ td::Result<KeyStorage::Key> KeyStorage::save_key(const DecryptedKey &decrypted_k
|
||||||
Key res;
|
Key res;
|
||||||
res.public_key = encrypted_key.public_key.as_octet_string();
|
res.public_key = encrypted_key.public_key.as_octet_string();
|
||||||
res.secret = std::move(encrypted_key.secret);
|
res.secret = std::move(encrypted_key.secret);
|
||||||
TRY_STATUS(kv_->set(to_file_name(res), encrypted_key.encrypted_data));
|
TRY_STATUS_PREFIX(kv_->set(to_file_name(res), encrypted_key.encrypted_data), TonlibError::Internal());
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,14 +71,16 @@ td::Result<DecryptedKey> KeyStorage::export_decrypted_key(InputKey input_key) {
|
||||||
if (r_encrypted_data.is_ok()) {
|
if (r_encrypted_data.is_ok()) {
|
||||||
LOG(WARNING) << "Restore private from deprecated location " << to_file_name_old(input_key.key) << " --> "
|
LOG(WARNING) << "Restore private from deprecated location " << to_file_name_old(input_key.key) << " --> "
|
||||||
<< to_file_name(input_key.key);
|
<< to_file_name(input_key.key);
|
||||||
TRY_STATUS(kv_->set(to_file_name(input_key.key), r_encrypted_data.ok()));
|
TRY_STATUS_PREFIX(kv_->set(to_file_name(input_key.key), r_encrypted_data.ok()), TonlibError::Internal());
|
||||||
kv_->erase(to_file_name_old(input_key.key)).ignore();
|
kv_->erase(to_file_name_old(input_key.key)).ignore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TRY_RESULT(encrypted_data, std::move(r_encrypted_data));
|
TRY_RESULT_PREFIX(encrypted_data, std::move(r_encrypted_data), TonlibError::KeyUnknown());
|
||||||
EncryptedKey encrypted_key{std::move(encrypted_data), td::Ed25519::PublicKey(std::move(input_key.key.public_key)),
|
EncryptedKey encrypted_key{std::move(encrypted_data), td::Ed25519::PublicKey(std::move(input_key.key.public_key)),
|
||||||
std::move(input_key.key.secret)};
|
std::move(input_key.key.secret)};
|
||||||
return encrypted_key.decrypt(std::move(input_key.local_password));
|
TRY_RESULT_PREFIX(decrypted_key, encrypted_key.decrypt(std::move(input_key.local_password)),
|
||||||
|
TonlibError::KeyDecrypt());
|
||||||
|
return std::move(decrypted_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Result<KeyStorage::ExportedKey> KeyStorage::export_key(InputKey input_key) {
|
td::Result<KeyStorage::ExportedKey> KeyStorage::export_key(InputKey input_key) {
|
||||||
|
@ -93,24 +98,43 @@ td::Result<KeyStorage::PrivateKey> KeyStorage::load_private_key(InputKey input_k
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status KeyStorage::delete_key(const Key &key) {
|
td::Status KeyStorage::delete_key(const Key &key) {
|
||||||
|
LOG(WARNING) << "Delete private key stored at " << to_file_name(key);
|
||||||
return kv_->erase(to_file_name(key));
|
return kv_->erase(to_file_name(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td::Status KeyStorage::delete_all_keys() {
|
||||||
|
std::vector<std::string> keys;
|
||||||
|
kv_->foreach_key([&](td::Slice key) {
|
||||||
|
if (td::PathView(key).extension().empty()) {
|
||||||
|
keys.push_back(key.str());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
td::Status status;
|
||||||
|
for (auto key : keys) {
|
||||||
|
LOG(WARNING) << "Delete private key stored at " << key;
|
||||||
|
auto err = kv_->erase(key);
|
||||||
|
if (err.is_error() && status.is_ok()) {
|
||||||
|
status = std::move(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
td::Result<KeyStorage::Key> KeyStorage::import_key(td::Slice local_password, td::Slice mnemonic_password,
|
td::Result<KeyStorage::Key> KeyStorage::import_key(td::Slice local_password, td::Slice mnemonic_password,
|
||||||
ExportedKey exported_key) {
|
ExportedKey exported_key) {
|
||||||
TRY_RESULT(mnemonic, Mnemonic::create(std::move(exported_key.mnemonic_words), td::SecureString(mnemonic_password)));
|
TRY_RESULT(mnemonic, Mnemonic::create(std::move(exported_key.mnemonic_words), td::SecureString(mnemonic_password)));
|
||||||
if (!mnemonic.is_basic_seed()) {
|
if (!mnemonic.is_basic_seed()) {
|
||||||
if (mnemonic_password.empty() && mnemonic.is_password_seed()) {
|
if (mnemonic_password.empty() && mnemonic.is_password_seed()) {
|
||||||
return td::Status::Error("Mnemonic password is expected");
|
return TonlibError::NeedMnemonicPassword();
|
||||||
}
|
}
|
||||||
return td::Status::Error("Invalid mnemonic words or password (invalid checksum)");
|
return TonlibError::InvalidMnemonic();
|
||||||
}
|
}
|
||||||
return save_key(DecryptedKey(std::move(mnemonic)), local_password);
|
return save_key(DecryptedKey(std::move(mnemonic)), local_password);
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Result<KeyStorage::ExportedPemKey> KeyStorage::export_pem_key(InputKey input_key, td::Slice key_password) {
|
td::Result<KeyStorage::ExportedPemKey> KeyStorage::export_pem_key(InputKey input_key, td::Slice key_password) {
|
||||||
TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
|
TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
|
||||||
TRY_RESULT(pem, decrypted_key.private_key.as_pem(key_password));
|
TRY_RESULT_PREFIX(pem, decrypted_key.private_key.as_pem(key_password), TonlibError::Internal());
|
||||||
return ExportedPemKey{std::move(pem)};
|
return ExportedPemKey{std::move(pem)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,14 +144,15 @@ td::Result<KeyStorage::Key> KeyStorage::change_local_password(InputKey input_key
|
||||||
Key res;
|
Key res;
|
||||||
res.public_key = std::move(input_key.key.public_key);
|
res.public_key = std::move(input_key.key.public_key);
|
||||||
res.secret = std::move(new_secret);
|
res.secret = std::move(new_secret);
|
||||||
TRY_RESULT(value, kv_->get(to_file_name(input_key.key)));
|
TRY_RESULT_PREFIX(value, kv_->get(to_file_name(input_key.key)), TonlibError::KeyUnknown());
|
||||||
TRY_STATUS(kv_->add(to_file_name(res), value));
|
TRY_STATUS_PREFIX(kv_->add(to_file_name(res), value), TonlibError::Internal());
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Result<KeyStorage::Key> KeyStorage::import_pem_key(td::Slice local_password, td::Slice key_password,
|
td::Result<KeyStorage::Key> KeyStorage::import_pem_key(td::Slice local_password, td::Slice key_password,
|
||||||
ExportedPemKey exported_key) {
|
ExportedPemKey exported_key) {
|
||||||
TRY_RESULT(key, td::Ed25519::PrivateKey::from_pem(exported_key.pem, key_password));
|
TRY_RESULT_PREFIX(key, td::Ed25519::PrivateKey::from_pem(exported_key.pem, key_password),
|
||||||
|
TonlibError::InvalidPemKey());
|
||||||
return save_key(DecryptedKey({}, std::move(key)), local_password);
|
return save_key(DecryptedKey({}, std::move(key)), local_password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +168,7 @@ td::Result<KeyStorage::Key> KeyStorage::import_encrypted_key(td::Slice local_pas
|
||||||
ExportedEncryptedKey exported_key) {
|
ExportedEncryptedKey exported_key) {
|
||||||
EncryptedKey encrypted_key{std::move(exported_key.data), td::Ed25519::PublicKey(td::SecureString()),
|
EncryptedKey encrypted_key{std::move(exported_key.data), td::Ed25519::PublicKey(td::SecureString()),
|
||||||
td::SecureString(dummy_secret)};
|
td::SecureString(dummy_secret)};
|
||||||
TRY_RESULT(decrypted_key, encrypted_key.decrypt(key_password, false));
|
TRY_RESULT_PREFIX(decrypted_key, encrypted_key.decrypt(key_password, false), TonlibError::KeyDecrypt());
|
||||||
return save_key(std::move(decrypted_key), local_password);
|
return save_key(std::move(decrypted_key), local_password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ class KeyStorage {
|
||||||
td::Result<Key> change_local_password(InputKey input_key, td::Slice new_local_password);
|
td::Result<Key> change_local_password(InputKey input_key, td::Slice new_local_password);
|
||||||
|
|
||||||
td::Status delete_key(const Key& key);
|
td::Status delete_key(const Key& key);
|
||||||
|
td::Status delete_all_keys();
|
||||||
|
|
||||||
td::Result<Key> import_key(td::Slice local_password, td::Slice mnemonic_password, ExportedKey exported_key);
|
td::Result<Key> import_key(td::Slice local_password, td::Slice mnemonic_password, ExportedKey exported_key);
|
||||||
td::Result<Key> import_pem_key(td::Slice local_password, td::Slice key_password, ExportedPemKey exported_key);
|
td::Result<Key> import_pem_key(td::Slice local_password, td::Slice key_password, ExportedPemKey exported_key);
|
||||||
|
|
|
@ -42,6 +42,22 @@ class KeyValueDir : public KeyValue {
|
||||||
return td::unlink(key.str());
|
return td::unlink(key.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void foreach_key(std::function<void(td::Slice)> f) override {
|
||||||
|
int cnt = 0;
|
||||||
|
td::WalkPath::run(directory_, [&](td::Slice path, td::WalkPath::Type type) {
|
||||||
|
cnt++;
|
||||||
|
if (type == td::WalkPath::Type::EnterDir) {
|
||||||
|
if (cnt != 1) {
|
||||||
|
return td::WalkPath::Action::SkipDir;
|
||||||
|
}
|
||||||
|
} else if (type == td::WalkPath::Type::NotDir) {
|
||||||
|
f(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return td::WalkPath::Action::Continue;
|
||||||
|
}).ignore();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string directory_;
|
std::string directory_;
|
||||||
|
|
||||||
|
@ -82,6 +98,11 @@ class KeyValueInmemory : public KeyValue {
|
||||||
map_.erase(it);
|
map_.erase(it);
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
void foreach_key(std::function<void(td::Slice)> f) override {
|
||||||
|
for (auto &it : map_) {
|
||||||
|
f(it.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Cmp : public std::less<> {
|
class Cmp : public std::less<> {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "td/utils/Slice.h"
|
#include "td/utils/Slice.h"
|
||||||
#include "td/utils/Status.h"
|
#include "td/utils/Status.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
class KeyValue {
|
class KeyValue {
|
||||||
public:
|
public:
|
||||||
|
@ -11,6 +13,7 @@ class KeyValue {
|
||||||
virtual td::Status set(td::Slice key, td::Slice value) = 0;
|
virtual td::Status set(td::Slice key, td::Slice value) = 0;
|
||||||
virtual td::Status erase(td::Slice key) = 0;
|
virtual td::Status erase(td::Slice key) = 0;
|
||||||
virtual td::Result<td::SecureString> get(td::Slice key) = 0;
|
virtual td::Result<td::SecureString> get(td::Slice key) = 0;
|
||||||
|
virtual void foreach_key(std::function<void(td::Slice)> f) = 0;
|
||||||
|
|
||||||
static td::Result<td::unique_ptr<KeyValue>> create_dir(td::CSlice dir);
|
static td::Result<td::unique_ptr<KeyValue>> create_dir(td::CSlice dir);
|
||||||
static td::Result<td::unique_ptr<KeyValue>> create_inmemory();
|
static td::Result<td::unique_ptr<KeyValue>> create_inmemory();
|
||||||
|
|
|
@ -18,12 +18,18 @@
|
||||||
*/
|
*/
|
||||||
#include "tonlib/LastBlock.h"
|
#include "tonlib/LastBlock.h"
|
||||||
|
|
||||||
|
#include "tonlib/utils.h"
|
||||||
|
|
||||||
#include "ton/lite-tl.hpp"
|
#include "ton/lite-tl.hpp"
|
||||||
|
|
||||||
#include "lite-client/lite-client-common.h"
|
#include "lite-client/lite-client-common.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
|
|
||||||
|
// init_state <-> last_key_block
|
||||||
|
// state.valitated_init_state
|
||||||
|
// last_key_block ->
|
||||||
|
//
|
||||||
td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) {
|
td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state) {
|
||||||
return sb << td::tag("last_block", state.last_block_id.to_str())
|
return sb << td::tag("last_block", state.last_block_id.to_str())
|
||||||
<< td::tag("last_key_block", state.last_key_block_id.to_str()) << td::tag("utime", state.utime);
|
<< td::tag("last_key_block", state.last_key_block_id.to_str()) << td::tag("utime", state.utime);
|
||||||
|
@ -32,9 +38,10 @@ td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state
|
||||||
LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, td::unique_ptr<Callback> callback)
|
LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, td::unique_ptr<Callback> callback)
|
||||||
: state_(std::move(state)), config_(std::move(config)), callback_(std::move(callback)) {
|
: state_(std::move(state)), config_(std::move(config)), callback_(std::move(callback)) {
|
||||||
client_.set_client(client);
|
client_.set_client(client);
|
||||||
if (!config_.init_block_id.is_valid()) {
|
state_.last_block_id = state_.last_key_block_id;
|
||||||
check_init_block_state_ = QueryState::Done;
|
|
||||||
}
|
VLOG(last_block) << "check_init_block: skip - FIXME before release";
|
||||||
|
check_init_block_state_ = QueryState::Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
|
void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
|
||||||
|
@ -42,9 +49,13 @@ void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
|
||||||
promise.set_error(fatal_error_.clone());
|
promise.set_error(fatal_error_.clone());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (promises_.empty() && get_last_block_state_ == QueryState::Done) {
|
if (promises_.empty() && get_last_block_state_ == QueryState::Done) {
|
||||||
|
VLOG(last_block) << "sync: start";
|
||||||
|
VLOG(last_block) << "get_last_block: reset";
|
||||||
get_last_block_state_ = QueryState::Empty;
|
get_last_block_state_ = QueryState::Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
promises_.push_back(std::move(promise));
|
promises_.push_back(std::move(promise));
|
||||||
sync_loop();
|
sync_loop();
|
||||||
}
|
}
|
||||||
|
@ -54,36 +65,43 @@ void LastBlock::sync_loop() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_zero_state(state_.zero_state_id);
|
update_zero_state(state_.zero_state_id, "cache");
|
||||||
update_zero_state(ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash,
|
update_zero_state(ton::ZeroStateIdExt(config_.zero_state_id.id.workchain, config_.zero_state_id.root_hash,
|
||||||
config_.zero_state_id.file_hash));
|
config_.zero_state_id.file_hash),
|
||||||
|
"config");
|
||||||
|
|
||||||
if (get_mc_info_state_ == QueryState::Empty) {
|
if (get_mc_info_state_ == QueryState::Empty) {
|
||||||
|
VLOG(last_block) << "get_masterchain_info: start";
|
||||||
get_mc_info_state_ = QueryState::Active;
|
get_mc_info_state_ = QueryState::Active;
|
||||||
client_.send_query(ton::lite_api::liteServer_getMasterchainInfo(),
|
client_.send_query(ton::lite_api::liteServer_getMasterchainInfo(),
|
||||||
[this](auto r_info) { this->on_masterchain_info(std::move(r_info)); });
|
[this](auto r_info) { this->on_masterchain_info(std::move(r_info)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_last_block_state_ == QueryState::Empty) {
|
if (check_init_block_state_ == QueryState::Empty) {
|
||||||
get_last_block_state_ = QueryState::Active;
|
if (!config_.init_block_id.is_valid()) {
|
||||||
total_sync_ = td::Timer();
|
check_init_block_state_ = QueryState::Done;
|
||||||
validate_ = td::Timer(true);
|
VLOG(last_block) << "check_init_block: skip - no init_block in config";
|
||||||
queries_ = 0;
|
} else if (config_.init_block_id == state_.init_block_id) {
|
||||||
LOG(INFO) << "Begin last block synchronization " << state_;
|
check_init_block_state_ = QueryState::Done;
|
||||||
do_get_last_block();
|
VLOG(last_block) << "check_init_block: skip - was checked before";
|
||||||
|
} else {
|
||||||
|
check_init_block_state_ = QueryState::Active;
|
||||||
|
check_init_block_stats_.start();
|
||||||
|
if (state_.last_block_id.id.seqno >= config_.init_block_id.id.seqno) {
|
||||||
|
VLOG(last_block) << "check_init_block: start - init_block -> last_block";
|
||||||
|
do_check_init_block(config_.init_block_id, state_.last_key_block_id);
|
||||||
|
} else {
|
||||||
|
VLOG(last_block) << "check_init_block: start - last_block -> init_block";
|
||||||
|
do_check_init_block(state_.last_key_block_id, config_.init_block_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_init_block_state_ == QueryState::Empty) {
|
if (get_last_block_state_ == QueryState::Empty && check_init_block_state_ == QueryState::Done) {
|
||||||
if (state_.last_block_id.id.seqno >= config_.init_block_id.id.seqno) {
|
VLOG(last_block) << "get_last_block: start";
|
||||||
check_init_block_state_ = QueryState::Active;
|
get_last_block_stats_.start();
|
||||||
// validate
|
get_last_block_state_ = QueryState::Active;
|
||||||
//total_sync_ = td::Timer();
|
do_get_last_block();
|
||||||
//validate_ = td::Timer(true);
|
|
||||||
//queries_ = 0;
|
|
||||||
LOG(INFO) << "Begin last block synchronization (check init_block)" << state_;
|
|
||||||
do_check_init_block(state_.last_key_block_id);
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_mc_info_state_ == QueryState::Done && get_last_block_state_ == QueryState::Done &&
|
if (get_mc_info_state_ == QueryState::Done && get_last_block_state_ == QueryState::Done &&
|
||||||
|
@ -94,7 +112,8 @@ void LastBlock::sync_loop() {
|
||||||
|
|
||||||
void LastBlock::do_get_last_block() {
|
void LastBlock::do_get_last_block() {
|
||||||
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
||||||
queries_++;
|
VLOG(last_block) << "get_last_block: continue " << state_.last_key_block_id.to_str() << " -> ?";
|
||||||
|
get_last_block_stats_.queries_++;
|
||||||
client_.send_query(
|
client_.send_query(
|
||||||
ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr),
|
ton::lite_api::liteServer_getBlockProof(0, create_tl_lite_block_id(state_.last_key_block_id), nullptr),
|
||||||
[this, from = state_.last_key_block_id](auto r_block_proof) {
|
[this, from = state_.last_key_block_id](auto r_block_proof) {
|
||||||
|
@ -102,64 +121,69 @@ void LastBlock::do_get_last_block() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastBlock::do_check_init_block(ton::BlockIdExt from) {
|
void LastBlock::do_check_init_block(ton::BlockIdExt from, ton::BlockIdExt to) {
|
||||||
|
VLOG(last_block) << "check_init_block: continue " << from.to_str() << " -> " << to.to_str();
|
||||||
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
//liteServer.getBlockProof mode:# known_block:tonNode.blockIdExt target_block:mode.0?tonNode.blockIdExt = liteServer.PartialBlockProof;
|
||||||
//queries_++;
|
check_init_block_stats_.queries_++;
|
||||||
client_.send_query(ton::lite_api::liteServer_getBlockProof(1, create_tl_lite_block_id(from),
|
client_.send_query(
|
||||||
create_tl_lite_block_id(config_.init_block_id)),
|
ton::lite_api::liteServer_getBlockProof(1, create_tl_lite_block_id(from), create_tl_lite_block_id(to)),
|
||||||
[this, from = state_.last_key_block_id](auto r_block_proof) {
|
[this, from, to](auto r_block_proof) { this->on_init_block_proof(from, to, std::move(r_block_proof)); });
|
||||||
this->on_init_block_proof(from, std::move(r_block_proof));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Result<std::unique_ptr<block::BlockProofChain>> LastBlock::process_block_proof(
|
td::Result<std::unique_ptr<block::BlockProofChain>> LastBlock::process_block_proof(
|
||||||
ton::BlockIdExt from,
|
ton::BlockIdExt from,
|
||||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||||
TRY_RESULT(block_proof, std::move(r_block_proof));
|
TRY_RESULT(block_proof, std::move(r_block_proof)); //TODO: it is fatal?
|
||||||
LOG(DEBUG) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_);
|
TRY_RESULT_PREFIX(chain, TRY_VM(process_block_proof(from, std::move(block_proof))),
|
||||||
|
TonlibError::ValidateBlockProof());
|
||||||
|
return std::move(chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
td::Result<std::unique_ptr<block::BlockProofChain>> LastBlock::process_block_proof(
|
||||||
|
ton::BlockIdExt from, ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof> block_proof) {
|
||||||
|
VLOG(last_block) << "Got proof FROM\n" << to_string(block_proof->from_) << "TO\n" << to_string(block_proof->to_);
|
||||||
TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof)));
|
TRY_RESULT(chain, liteclient::deserialize_proof_chain(std::move(block_proof)));
|
||||||
if (chain->from != from) {
|
if (chain->from != from) {
|
||||||
return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str()
|
return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str()
|
||||||
<< ", not from requested block " << from.to_str());
|
<< ", not from requested block " << from.to_str());
|
||||||
}
|
}
|
||||||
TRY_STATUS(chain->validate());
|
TRY_STATUS(chain->validate());
|
||||||
|
return std::move(chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LastBlock::update_state(block::BlockProofChain& chain) {
|
||||||
|
// Update state_
|
||||||
bool is_changed = false;
|
bool is_changed = false;
|
||||||
is_changed |= update_mc_last_block(chain->to);
|
is_changed |= update_mc_last_block(chain.to);
|
||||||
if (chain->has_key_block) {
|
if (chain.has_key_block) {
|
||||||
is_changed |= update_mc_last_key_block(chain->key_blkid);
|
is_changed |= update_mc_last_key_block(chain.key_blkid);
|
||||||
}
|
}
|
||||||
if (chain->has_utime) {
|
if (chain.has_utime) {
|
||||||
update_utime(chain->last_utime);
|
update_utime(chain.last_utime);
|
||||||
}
|
}
|
||||||
if (is_changed) {
|
if (is_changed) {
|
||||||
callback_->on_state_changed(state_);
|
callback_->on_state_changed(state_);
|
||||||
}
|
}
|
||||||
return std::move(chain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastBlock::on_block_proof(
|
void LastBlock::on_block_proof(
|
||||||
ton::BlockIdExt from,
|
ton::BlockIdExt from,
|
||||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||||
validate_.resume();
|
get_last_block_stats_.validate_.resume();
|
||||||
auto r_chain = process_block_proof(from, std::move(r_block_proof));
|
auto r_chain = process_block_proof(from, std::move(r_block_proof));
|
||||||
validate_.pause();
|
get_last_block_stats_.validate_.pause();
|
||||||
bool is_ready;
|
|
||||||
if (r_chain.is_error()) {
|
if (r_chain.is_error()) {
|
||||||
LOG(WARNING) << "Error during last block synchronization " << r_chain.error();
|
get_last_block_state_ = QueryState::Empty;
|
||||||
if (config_.init_block_id.is_valid()) {
|
VLOG(last_block) << "get_last_block: error " << r_chain.error();
|
||||||
if (state_.last_key_block_id.id.seqno < config_.init_block_id.id.seqno) {
|
on_sync_error(r_chain.move_as_error_suffix("(during last block synchronization)"));
|
||||||
on_sync_error(td::Status::Error(PSLICE() << "Sync failed and we can't validate config.init_block: "
|
return;
|
||||||
<< r_chain.move_as_error()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is_ready = true;
|
|
||||||
} else {
|
|
||||||
is_ready = r_chain.ok()->complete;
|
|
||||||
}
|
}
|
||||||
if (is_ready) {
|
|
||||||
LOG(INFO) << "End last block synchronization " << state_ << "\n"
|
auto chain = r_chain.move_as_ok();
|
||||||
<< " net queries: " << queries_ << "\n"
|
CHECK(chain);
|
||||||
<< " total: " << total_sync_ << " validation: " << validate_;
|
update_state(*chain);
|
||||||
|
if (chain->complete) {
|
||||||
|
VLOG(last_block) << "get_last_block: done\n" << get_last_block_stats_;
|
||||||
get_last_block_state_ = QueryState::Done;
|
get_last_block_state_ = QueryState::Done;
|
||||||
sync_loop();
|
sync_loop();
|
||||||
} else {
|
} else {
|
||||||
|
@ -168,26 +192,26 @@ void LastBlock::on_block_proof(
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastBlock::on_init_block_proof(
|
void LastBlock::on_init_block_proof(
|
||||||
ton::BlockIdExt from,
|
ton::BlockIdExt from, ton::BlockIdExt to,
|
||||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof) {
|
||||||
validate_.resume();
|
check_init_block_stats_.validate_.resume();
|
||||||
auto r_chain = process_block_proof(from, std::move(r_block_proof));
|
auto r_chain = process_block_proof(from, std::move(r_block_proof));
|
||||||
validate_.pause();
|
check_init_block_stats_.validate_.pause();
|
||||||
if (r_chain.is_error()) {
|
if (r_chain.is_error()) {
|
||||||
check_init_block_state_ = QueryState::Empty;
|
check_init_block_state_ = QueryState::Empty;
|
||||||
on_sync_error(
|
VLOG(last_block) << "check_init_block: error " << r_chain.error();
|
||||||
td::Status::Error(PSLICE() << "Error during last block synchronization (check init_block)" << r_chain.error()));
|
on_sync_error(r_chain.move_as_error_suffix("(during check init block)"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto chain = r_chain.move_as_ok();
|
auto chain = r_chain.move_as_ok();
|
||||||
|
CHECK(chain);
|
||||||
|
update_state(*chain);
|
||||||
if (chain->complete) {
|
if (chain->complete) {
|
||||||
LOG(INFO) << "End last block synchronization " << state_ << "\n"
|
VLOG(last_block) << "check_init_block: done\n" << check_init_block_stats_;
|
||||||
<< " net queries: " << queries_ << "\n"
|
check_init_block_state_ = QueryState::Done;
|
||||||
<< " total: " << total_sync_ << " validation: " << validate_;
|
|
||||||
get_last_block_state_ = QueryState::Done;
|
|
||||||
sync_loop();
|
sync_loop();
|
||||||
} else {
|
} else {
|
||||||
do_check_init_block(chain->to);
|
do_check_init_block(chain->to, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,28 +219,30 @@ void LastBlock::on_masterchain_info(
|
||||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info) {
|
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info) {
|
||||||
if (r_info.is_ok()) {
|
if (r_info.is_ok()) {
|
||||||
auto info = r_info.move_as_ok();
|
auto info = r_info.move_as_ok();
|
||||||
update_zero_state(create_zero_state_id(info->init_));
|
update_zero_state(create_zero_state_id(info->init_), "masterchain info");
|
||||||
update_mc_last_block(create_block_id(info->last_));
|
// last block is not validated! Do not update it
|
||||||
get_mc_info_state_ = QueryState::Done;
|
get_mc_info_state_ = QueryState::Done;
|
||||||
|
VLOG(last_block) << "get_masterchain_info: done";
|
||||||
} else {
|
} else {
|
||||||
get_mc_info_state_ = QueryState::Empty;
|
get_mc_info_state_ = QueryState::Empty;
|
||||||
|
VLOG(last_block) << "get_masterchain_info: error " << r_info.error();
|
||||||
LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error();
|
LOG(WARNING) << "Failed liteServer_getMasterchainInfo " << r_info.error();
|
||||||
on_sync_error(r_info.move_as_error());
|
on_sync_error(r_info.move_as_error());
|
||||||
}
|
}
|
||||||
sync_loop();
|
sync_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) {
|
void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id, td::Slice source) {
|
||||||
if (has_fatal_error()) {
|
if (has_fatal_error()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!zero_state_id.is_valid()) {
|
if (!zero_state_id.is_valid()) {
|
||||||
LOG(ERROR) << "Ignore invalid zero state update";
|
LOG(ERROR) << "Ignore invalid zero state update from " << source;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state_.zero_state_id.is_valid()) {
|
if (!state_.zero_state_id.is_valid()) {
|
||||||
LOG(INFO) << "Init zerostate: " << zero_state_id.to_str();
|
LOG(INFO) << "Init zerostate from " << source << ": " << zero_state_id.to_str();
|
||||||
state_.zero_state_id = std::move(zero_state_id);
|
state_.zero_state_id = std::move(zero_state_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -225,8 +251,9 @@ void LastBlock::update_zero_state(ton::ZeroStateIdExt zero_state_id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
on_fatal_error(td::Status::Error(PSLICE() << "Masterchain zerostate mismatch: expected: "
|
on_fatal_error(TonlibError::ValidateZeroState(PSLICE() << "Masterchain zerostate mismatch: expected: "
|
||||||
<< state_.zero_state_id.to_str() << ", found " << zero_state_id.to_str()));
|
<< state_.zero_state_id.to_str() << ", found "
|
||||||
|
<< zero_state_id.to_str() << " from " << source));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) {
|
bool LastBlock::update_mc_last_block(ton::BlockIdExt mc_block_id) {
|
||||||
|
@ -256,6 +283,9 @@ bool LastBlock::update_mc_last_key_block(ton::BlockIdExt mc_key_block_id) {
|
||||||
if (!state_.last_key_block_id.is_valid() || state_.last_key_block_id.id.seqno < mc_key_block_id.id.seqno) {
|
if (!state_.last_key_block_id.is_valid() || state_.last_key_block_id.id.seqno < mc_key_block_id.id.seqno) {
|
||||||
state_.last_key_block_id = mc_key_block_id;
|
state_.last_key_block_id = mc_key_block_id;
|
||||||
LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str();
|
LOG(INFO) << "Update masterchain key block id: " << state_.last_key_block_id.to_str();
|
||||||
|
//LOG(ERROR) << td::int64(state_.last_key_block_id.id.shard) << " "
|
||||||
|
//<< td::base64_encode(state_.last_key_block_id.file_hash.as_slice()) << " "
|
||||||
|
//<< td::base64_encode(state_.last_key_block_id.root_hash.as_slice());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -268,6 +298,7 @@ void LastBlock::update_utime(td::int64 utime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastBlock::on_sync_ok() {
|
void LastBlock::on_sync_ok() {
|
||||||
|
VLOG(last_block) << "sync: ok " << state_;
|
||||||
for (auto& promise : promises_) {
|
for (auto& promise : promises_) {
|
||||||
auto state = state_;
|
auto state = state_;
|
||||||
promise.set_value(std::move(state));
|
promise.set_value(std::move(state));
|
||||||
|
@ -275,12 +306,14 @@ void LastBlock::on_sync_ok() {
|
||||||
promises_.clear();
|
promises_.clear();
|
||||||
}
|
}
|
||||||
void LastBlock::on_sync_error(td::Status status) {
|
void LastBlock::on_sync_error(td::Status status) {
|
||||||
|
VLOG(last_block) << "sync: error " << status;
|
||||||
for (auto& promise : promises_) {
|
for (auto& promise : promises_) {
|
||||||
promise.set_error(status.clone());
|
promise.set_error(status.clone());
|
||||||
}
|
}
|
||||||
promises_.clear();
|
promises_.clear();
|
||||||
}
|
}
|
||||||
void LastBlock::on_fatal_error(td::Status status) {
|
void LastBlock::on_fatal_error(td::Status status) {
|
||||||
|
VLOG(last_block) << "sync: fatal error " << status;
|
||||||
fatal_error_ = std::move(status);
|
fatal_error_ = std::move(status);
|
||||||
on_sync_error(fatal_error_.clone());
|
on_sync_error(fatal_error_.clone());
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "tonlib/Config.h"
|
#include "tonlib/Config.h"
|
||||||
#include "tonlib/ExtClient.h"
|
#include "tonlib/ExtClient.h"
|
||||||
|
|
||||||
|
#include "td/utils/tl_helpers.h"
|
||||||
|
|
||||||
namespace block {
|
namespace block {
|
||||||
struct BlockProofChain;
|
struct BlockProofChain;
|
||||||
}
|
}
|
||||||
|
@ -89,25 +91,44 @@ struct LastBlockState {
|
||||||
ton::BlockIdExt last_key_block_id;
|
ton::BlockIdExt last_key_block_id;
|
||||||
ton::BlockIdExt last_block_id;
|
ton::BlockIdExt last_block_id;
|
||||||
td::int64 utime{0};
|
td::int64 utime{0};
|
||||||
|
ton::BlockIdExt init_block_id;
|
||||||
|
|
||||||
|
static constexpr td::int32 magic = 0xa7f171a4;
|
||||||
|
enum Version { None = 0, Magic, InitBlock, Next };
|
||||||
|
static constexpr td::int32 version = Version::Next - 1;
|
||||||
|
|
||||||
template <class StorerT>
|
template <class StorerT>
|
||||||
void store(StorerT &storer) const {
|
void store(StorerT &storer) const {
|
||||||
using td::store;
|
using td::store;
|
||||||
using tonlib::store;
|
using tonlib::store;
|
||||||
|
store(magic, storer);
|
||||||
|
store(version, storer);
|
||||||
|
|
||||||
store(zero_state_id, storer);
|
store(zero_state_id, storer);
|
||||||
store(last_key_block_id, storer);
|
store(last_key_block_id, storer);
|
||||||
store(last_block_id, storer);
|
store(last_block_id, storer);
|
||||||
store(utime, storer);
|
store(utime, storer);
|
||||||
|
store(init_block_id, storer);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ParserT>
|
template <class ParserT>
|
||||||
void parse(ParserT &parser) {
|
void parse(ParserT &parser) {
|
||||||
using td::parse;
|
using td::parse;
|
||||||
using tonlib::parse;
|
using tonlib::parse;
|
||||||
|
td::int32 version = 0;
|
||||||
|
if (parser.can_prefetch_int() && parser.prefetch_int_unsafe() == magic) {
|
||||||
|
td::int32 magic;
|
||||||
|
parse(magic, parser);
|
||||||
|
parse(version, parser);
|
||||||
|
}
|
||||||
|
|
||||||
parse(zero_state_id, parser);
|
parse(zero_state_id, parser);
|
||||||
parse(last_key_block_id, parser);
|
parse(last_key_block_id, parser);
|
||||||
parse(last_block_id, parser);
|
parse(last_block_id, parser);
|
||||||
parse(utime, parser);
|
parse(utime, parser);
|
||||||
|
if (version >= InitBlock) {
|
||||||
|
parse(init_block_id, parser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -132,20 +153,36 @@ class LastBlock : public td::actor::Actor {
|
||||||
td::Status fatal_error_;
|
td::Status fatal_error_;
|
||||||
|
|
||||||
enum class QueryState { Empty, Active, Done };
|
enum class QueryState { Empty, Active, Done };
|
||||||
QueryState get_mc_info_state_{QueryState::Empty};
|
QueryState get_mc_info_state_{QueryState::Empty}; // just to check zero state
|
||||||
QueryState get_last_block_state_{QueryState::Empty};
|
QueryState check_init_block_state_{QueryState::Empty}; // init_block <---> last_key_block (from older to newer)
|
||||||
QueryState check_init_block_state_{QueryState::Empty};
|
QueryState get_last_block_state_{QueryState::Empty}; // last_key_block_id --> ?
|
||||||
|
|
||||||
// stats
|
// stats
|
||||||
td::Timer total_sync_;
|
struct Stats {
|
||||||
td::Timer validate_;
|
td::Timer total_sync_;
|
||||||
td::uint32 queries_;
|
td::Timer validate_;
|
||||||
|
td::uint32 queries_;
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
total_sync_ = td::Timer();
|
||||||
|
validate_ = td::Timer(true);
|
||||||
|
queries_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend td::StringBuilder &operator<<(td::StringBuilder &sb, const Stats &stats) {
|
||||||
|
return sb << " net queries: " << stats.queries_ << "\n"
|
||||||
|
<< " total: " << stats.total_sync_ << " validation: " << stats.validate_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Stats check_init_block_stats_;
|
||||||
|
Stats get_last_block_stats_;
|
||||||
|
|
||||||
std::vector<td::Promise<LastBlockState>> promises_;
|
std::vector<td::Promise<LastBlockState>> promises_;
|
||||||
|
|
||||||
void do_check_init_block(ton::BlockIdExt from);
|
void do_check_init_block(ton::BlockIdExt from, ton::BlockIdExt to);
|
||||||
void on_init_block_proof(
|
void on_init_block_proof(
|
||||||
ton::BlockIdExt from,
|
ton::BlockIdExt from, ton::BlockIdExt to,
|
||||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof);
|
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof);
|
||||||
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
|
void on_masterchain_info(td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_masterchainInfo>> r_info);
|
||||||
void do_get_last_block();
|
void do_get_last_block();
|
||||||
|
@ -155,7 +192,11 @@ class LastBlock : public td::actor::Actor {
|
||||||
ton::BlockIdExt from,
|
ton::BlockIdExt from,
|
||||||
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof);
|
td::Result<ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof>> r_block_proof);
|
||||||
|
|
||||||
void update_zero_state(ton::ZeroStateIdExt zero_state_id);
|
td::Result<std::unique_ptr<block::BlockProofChain>> process_block_proof(
|
||||||
|
ton::BlockIdExt from, ton::ton_api::object_ptr<ton::lite_api::liteServer_partialBlockProof> block_proof);
|
||||||
|
|
||||||
|
void update_state(block::BlockProofChain &chain);
|
||||||
|
void update_zero_state(ton::ZeroStateIdExt zero_state_id, td::Slice source);
|
||||||
|
|
||||||
bool update_mc_last_block(ton::BlockIdExt mc_block_id);
|
bool update_mc_last_block(ton::BlockIdExt mc_block_id);
|
||||||
bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id);
|
bool update_mc_last_key_block(ton::BlockIdExt mc_key_block_id);
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
*/
|
*/
|
||||||
#include "LastBlockStorage.h"
|
#include "LastBlockStorage.h"
|
||||||
|
|
||||||
|
#include "tonlib/utils.h"
|
||||||
|
|
||||||
#include "td/utils/as.h"
|
#include "td/utils/as.h"
|
||||||
#include "td/utils/filesystem.h"
|
#include "td/utils/filesystem.h"
|
||||||
#include "td/utils/port/path.h"
|
#include "td/utils/port/path.h"
|
||||||
|
@ -49,6 +51,7 @@ td::Result<LastBlockState> LastBlockStorage::get_state(td::Slice name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastBlockStorage::save_state(td::Slice name, LastBlockState state) {
|
void LastBlockStorage::save_state(td::Slice name, LastBlockState state) {
|
||||||
|
VLOG(last_block) << "Save to cache: " << state;
|
||||||
auto x = td::serialize(state);
|
auto x = td::serialize(state);
|
||||||
std::string y(x.size() + 8, 0);
|
std::string y(x.size() + 8, 0);
|
||||||
td::MutableSlice(y).substr(8).copy_from(x);
|
td::MutableSlice(y).substr(8).copy_from(x);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
Copyright 2017-2019 Telegram Systems LLP
|
Copyright 2017-2019 Telegram Systems LLP
|
||||||
*/
|
*/
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include "auto/tl/tonlib_api.h"
|
#include "auto/tl/tonlib_api.h"
|
||||||
|
|
||||||
|
@ -36,11 +37,9 @@ static td::FileLog file_log;
|
||||||
static td::TsLog ts_log(&file_log);
|
static td::TsLog ts_log(&file_log);
|
||||||
static td::NullLog null_log;
|
static td::NullLog null_log;
|
||||||
|
|
||||||
td::int32 VERBOSITY_NAME(abc) = VERBOSITY_NAME(DEBUG);
|
|
||||||
td::int32 VERBOSITY_NAME(bcd) = VERBOSITY_NAME(DEBUG);
|
|
||||||
#define ADD_TAG(tag) \
|
#define ADD_TAG(tag) \
|
||||||
{ #tag, &VERBOSITY_NAME(tag) }
|
{ #tag, &VERBOSITY_NAME(tag) }
|
||||||
static const std::map<td::Slice, int *> log_tags{ADD_TAG(abc), ADD_TAG(bcd)};
|
static const std::map<td::Slice, int *> log_tags{ADD_TAG(tonlib_query), ADD_TAG(last_block)};
|
||||||
#undef ADD_TAG
|
#undef ADD_TAG
|
||||||
|
|
||||||
td::Status Logging::set_current_stream(tonlib_api::object_ptr<tonlib_api::LogStream> stream) {
|
td::Status Logging::set_current_stream(tonlib_api::object_ptr<tonlib_api::LogStream> stream) {
|
||||||
|
|
|
@ -22,18 +22,18 @@
|
||||||
#include "td/utils/base64.h"
|
#include "td/utils/base64.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
const block::StdAddress& TestGiver::address() {
|
const block::StdAddress& TestGiver::address() noexcept {
|
||||||
static block::StdAddress res =
|
static block::StdAddress res =
|
||||||
block::StdAddress::parse("kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny").move_as_ok();
|
block::StdAddress::parse("kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny").move_as_ok();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm::CellHash TestGiver::get_init_code_hash() {
|
vm::CellHash TestGiver::get_init_code_hash() noexcept {
|
||||||
return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok());
|
return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
td::Ref<vm::Cell> TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||||
const block::StdAddress& dest_address) {
|
const block::StdAddress& dest_address) noexcept {
|
||||||
td::BigInt256 dest_addr;
|
td::BigInt256 dest_addr;
|
||||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
|
|
|
@ -23,9 +23,9 @@ namespace tonlib {
|
||||||
class TestGiver {
|
class TestGiver {
|
||||||
public:
|
public:
|
||||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||||
static const block::StdAddress& address();
|
static const block::StdAddress& address() noexcept;
|
||||||
static vm::CellHash get_init_code_hash();
|
static vm::CellHash get_init_code_hash() noexcept;
|
||||||
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
static td::Ref<vm::Cell> make_a_gift_message(td::uint32 seqno, td::uint64 gramms, td::Slice message,
|
||||||
const block::StdAddress& dest_address);
|
const block::StdAddress& dest_address) noexcept;
|
||||||
};
|
};
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
#include "td/utils/base64.h"
|
#include "td/utils/base64.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
td::Ref<vm::Cell> TestWallet::get_init_state(const td::Ed25519::PublicKey& public_key) {
|
td::Ref<vm::Cell> TestWallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||||
auto code = get_init_code();
|
auto code = get_init_code();
|
||||||
auto data = get_init_data(public_key);
|
auto data = get_init_data(public_key);
|
||||||
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> TestWallet::get_init_message(const td::Ed25519::PrivateKey& private_key) {
|
td::Ref<vm::Cell> TestWallet::get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept {
|
||||||
std::string seq_no(4, 0);
|
std::string seq_no(4, 0);
|
||||||
auto signature =
|
auto signature =
|
||||||
private_key.sign(vm::CellBuilder().store_bytes(seq_no).finalize()->get_hash().as_slice()).move_as_ok();
|
private_key.sign(vm::CellBuilder().store_bytes(seq_no).finalize()->get_hash().as_slice()).move_as_ok();
|
||||||
|
@ -39,7 +39,7 @@ td::Ref<vm::Cell> TestWallet::get_init_message(const td::Ed25519::PrivateKey& pr
|
||||||
|
|
||||||
td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||||
td::int64 gramms, td::Slice message,
|
td::int64 gramms, td::Slice message,
|
||||||
const block::StdAddress& dest_address) {
|
const block::StdAddress& dest_address) noexcept {
|
||||||
td::BigInt256 dest_addr;
|
td::BigInt256 dest_addr;
|
||||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
|
@ -48,18 +48,22 @@ td::Ref<vm::Cell> TestWallet::make_a_gift_message(const td::Ed25519::PrivateKey&
|
||||||
.append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok())
|
.append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok())
|
||||||
.store_long(dest_address.workchain, 8)
|
.store_long(dest_address.workchain, 8)
|
||||||
.store_int256(dest_addr, 256);
|
.store_int256(dest_addr, 256);
|
||||||
|
td::int32 send_mode = 3;
|
||||||
|
if (gramms == -1) {
|
||||||
|
gramms = 0;
|
||||||
|
send_mode += 128;
|
||||||
|
}
|
||||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||||
cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4);
|
cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4);
|
||||||
vm::CellString::store(cb, message, 35 * 8).ensure();
|
vm::CellString::store(cb, message, 35 * 8).ensure();
|
||||||
auto message_inner = cb.finalize();
|
auto message_inner = cb.finalize();
|
||||||
td::int8 send_mode = 3;
|
|
||||||
auto message_outer =
|
auto message_outer =
|
||||||
vm::CellBuilder().store_long(seqno, 32).store_long(send_mode, 8).store_ref(message_inner).finalize();
|
vm::CellBuilder().store_long(seqno, 32).store_long(send_mode, 8).store_ref(message_inner).finalize();
|
||||||
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
|
||||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> TestWallet::get_init_code() {
|
td::Ref<vm::Cell> TestWallet::get_init_code() noexcept {
|
||||||
static auto res = [] {
|
static auto res = [] {
|
||||||
auto serialized_code = td::base64_decode(
|
auto serialized_code = td::base64_decode(
|
||||||
"te6ccgEEAQEAAAAAUwAAov8AIN0gggFMl7qXMO1E0NcLH+Ck8mCBAgDXGCDXCx/tRNDTH9P/"
|
"te6ccgEEAQEAAAAAUwAAov8AIN0gggFMl7qXMO1E0NcLH+Ck8mCBAgDXGCDXCx/tRNDTH9P/"
|
||||||
|
@ -70,11 +74,11 @@ td::Ref<vm::Cell> TestWallet::get_init_code() {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm::CellHash TestWallet::get_init_code_hash() {
|
vm::CellHash TestWallet::get_init_code_hash() noexcept {
|
||||||
return get_init_code()->get_hash();
|
return get_init_code()->get_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> TestWallet::get_init_data(const td::Ed25519::PublicKey& public_key) {
|
td::Ref<vm::Cell> TestWallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||||
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
||||||
}
|
}
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|
|
@ -27,14 +27,14 @@ namespace tonlib {
|
||||||
class TestWallet {
|
class TestWallet {
|
||||||
public:
|
public:
|
||||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||||
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key);
|
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||||
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key);
|
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept;
|
||||||
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||||
td::int64 gramms, td::Slice message,
|
td::int64 gramms, td::Slice message,
|
||||||
const block::StdAddress& dest_address);
|
const block::StdAddress& dest_address) noexcept;
|
||||||
|
|
||||||
static td::Ref<vm::Cell> get_init_code();
|
static td::Ref<vm::Cell> get_init_code() noexcept;
|
||||||
static vm::CellHash get_init_code_hash();
|
static vm::CellHash get_init_code_hash() noexcept;
|
||||||
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key);
|
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||||
};
|
};
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -47,13 +47,13 @@ class TonlibClient : public td::actor::Actor {
|
||||||
private:
|
private:
|
||||||
enum class State { Uninited, Running, Closed } state_ = State::Uninited;
|
enum class State { Uninited, Running, Closed } state_ = State::Uninited;
|
||||||
td::unique_ptr<TonlibCallback> callback_;
|
td::unique_ptr<TonlibCallback> callback_;
|
||||||
|
|
||||||
|
// Config
|
||||||
Config config_;
|
Config config_;
|
||||||
td::uint32 config_generation_{0};
|
td::uint32 config_generation_{0};
|
||||||
std::string blockchain_name_;
|
std::string blockchain_name_;
|
||||||
bool ignore_cache_{false};
|
bool ignore_cache_{false};
|
||||||
|
|
||||||
bool use_callbacks_for_network_{false};
|
bool use_callbacks_for_network_{false};
|
||||||
td::actor::ActorId<ExtClientOutbound> ext_client_outbound_;
|
|
||||||
|
|
||||||
// KeyStorage
|
// KeyStorage
|
||||||
std::shared_ptr<KeyValue> kv_;
|
std::shared_ptr<KeyValue> kv_;
|
||||||
|
@ -62,6 +62,7 @@ class TonlibClient : public td::actor::Actor {
|
||||||
|
|
||||||
// network
|
// network
|
||||||
td::actor::ActorOwn<ton::adnl::AdnlExtClient> raw_client_;
|
td::actor::ActorOwn<ton::adnl::AdnlExtClient> raw_client_;
|
||||||
|
td::actor::ActorId<ExtClientOutbound> ext_client_outbound_;
|
||||||
td::actor::ActorOwn<LastBlock> raw_last_block_;
|
td::actor::ActorOwn<LastBlock> raw_last_block_;
|
||||||
ExtClient client_;
|
ExtClient client_;
|
||||||
|
|
||||||
|
@ -158,6 +159,7 @@ class TonlibClient : public td::actor::Actor {
|
||||||
td::Status do_request(const tonlib_api::exportKey& request,
|
td::Status do_request(const tonlib_api::exportKey& request,
|
||||||
td::Promise<object_ptr<tonlib_api::exportedKey>>&& promise);
|
td::Promise<object_ptr<tonlib_api::exportedKey>>&& promise);
|
||||||
td::Status do_request(const tonlib_api::deleteKey& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
td::Status do_request(const tonlib_api::deleteKey& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||||
|
td::Status do_request(const tonlib_api::deleteAllKeys& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||||
td::Status do_request(const tonlib_api::importKey& request, td::Promise<object_ptr<tonlib_api::key>>&& promise);
|
td::Status do_request(const tonlib_api::importKey& request, td::Promise<object_ptr<tonlib_api::key>>&& promise);
|
||||||
|
|
||||||
td::Status do_request(const tonlib_api::exportPemKey& request,
|
td::Status do_request(const tonlib_api::exportPemKey& request,
|
||||||
|
|
157
tonlib/tonlib/TonlibError.h
Normal file
157
tonlib/tonlib/TonlibError.h
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
This file is part of TON Blockchain Library.
|
||||||
|
|
||||||
|
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Copyright 2017-2019 Telegram Systems LLP
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "td/utils/Status.h"
|
||||||
|
#include "common/errorcode.h"
|
||||||
|
// NEED_MNEMONIC_PASSWORD
|
||||||
|
// KEY_UNKNOWN
|
||||||
|
// KEY_DECRYPT
|
||||||
|
// INVALID_MNEMONIC
|
||||||
|
// INVALID_BAG_OF_CELLS
|
||||||
|
// INVALID_PUBLIC_KEY
|
||||||
|
// INVALID_ACCOUNT_ADDRESS
|
||||||
|
// INVALID_CONFIG
|
||||||
|
// INVALID_PEM_KEY
|
||||||
|
// MESSAGE_TOO_LONG
|
||||||
|
// EMPTY_FIELD
|
||||||
|
// INVALID_FIELD
|
||||||
|
// DANGEROUS_TRANSACTION
|
||||||
|
// ACCOUNT_NOT_INITED
|
||||||
|
// ACCOUNT_TYPE_UNKNOWN
|
||||||
|
// ACCOUNT_TYPE_UNEXPECTED
|
||||||
|
// VALIDATE_ACCOUNT_STATE
|
||||||
|
// VALIDATE_TRANSACTION
|
||||||
|
// VALIDATE_ZERO_STATE
|
||||||
|
// VALIDATE_BLOCK_PROOF
|
||||||
|
// NO_LITE_SERVERS
|
||||||
|
// LITE_SERVER_NETWORK
|
||||||
|
// CANCELLED
|
||||||
|
// NOT_ENOUGH_FUNDS
|
||||||
|
// LITE_SERVER
|
||||||
|
// INTERNAL
|
||||||
|
|
||||||
|
namespace tonlib {
|
||||||
|
struct TonlibError {
|
||||||
|
static td::Status NeedMnemonicPassword() {
|
||||||
|
return td::Status::Error(400, "NEED_MNEMONIC_PASSWORD");
|
||||||
|
}
|
||||||
|
static td::Status InvalidMnemonic() {
|
||||||
|
return td::Status::Error(400, "INVALID_MNEMONIC: Invalid mnemonic words or password (invalid checksum)");
|
||||||
|
}
|
||||||
|
static td::Status InvalidBagOfCells(td::Slice comment) {
|
||||||
|
return td::Status::Error(400, PSLICE() << "INVALID_BAG_OF_CELLS: " << comment);
|
||||||
|
}
|
||||||
|
static td::Status InvalidPublicKey() {
|
||||||
|
return td::Status::Error(400, "INVALID_PUBLIC_KEY");
|
||||||
|
}
|
||||||
|
static td::Status InvalidAccountAddress() {
|
||||||
|
return td::Status::Error(400, "INVALID_ACCOUNT_ADDRESS");
|
||||||
|
}
|
||||||
|
static td::Status InvalidConfig(td::Slice reason) {
|
||||||
|
return td::Status::Error(400, PSLICE() << "INVALID_CONFIG: " << reason);
|
||||||
|
}
|
||||||
|
static td::Status InvalidPemKey() {
|
||||||
|
return td::Status::Error(400, "INVALID_PEM_KEY");
|
||||||
|
}
|
||||||
|
static td::Status MessageTooLong() {
|
||||||
|
return td::Status::Error(400, "MESSAGE_TOO_LONG");
|
||||||
|
}
|
||||||
|
static td::Status EmptyField(td::Slice field_name) {
|
||||||
|
return td::Status::Error(400, PSLICE() << "EMPTY_FIELD: Field " << field_name << " must not be emtpy");
|
||||||
|
}
|
||||||
|
static td::Status InvalidField(td::Slice field_name, td::Slice reason) {
|
||||||
|
return td::Status::Error(400, PSLICE() << "INVALID_FIELD: Field " << field_name << " has invalid value " << reason);
|
||||||
|
}
|
||||||
|
static td::Status DangerousTransaction(td::Slice reason) {
|
||||||
|
return td::Status::Error(400, PSLICE() << "DANGEROUS_TRANSACTION: " << reason);
|
||||||
|
}
|
||||||
|
static td::Status AccountNotInited() {
|
||||||
|
return td::Status::Error(400, "ACCOUNT_NOT_INITED");
|
||||||
|
}
|
||||||
|
static td::Status AccountTypeUnknown() {
|
||||||
|
return td::Status::Error(400, "ACCOUNT_TYPE_UNKNOWN");
|
||||||
|
}
|
||||||
|
static td::Status AccountTypeUnexpected(td::Slice expected) {
|
||||||
|
return td::Status::Error(400, PSLICE() << "ACCOUNT_TYPE_UNEXPECTED: not a " << expected);
|
||||||
|
}
|
||||||
|
static td::Status Internal() {
|
||||||
|
return td::Status::Error(500, "INTERNAL");
|
||||||
|
}
|
||||||
|
static td::Status Internal(td::Slice message) {
|
||||||
|
return td::Status::Error(500, PSLICE() << "INTERNAL: " << message);
|
||||||
|
}
|
||||||
|
static td::Status KeyUnknown() {
|
||||||
|
return td::Status::Error(500, "KEY_UNKNOWN");
|
||||||
|
}
|
||||||
|
static td::Status KeyDecrypt() {
|
||||||
|
return td::Status::Error(500, "KEY_DECRYPT");
|
||||||
|
}
|
||||||
|
static td::Status ValidateAccountState() {
|
||||||
|
return td::Status::Error(500, "VALIDATE_ACCOUNT_STATE");
|
||||||
|
}
|
||||||
|
static td::Status ValidateTransactions() {
|
||||||
|
return td::Status::Error(500, "VALIDATE_TRANSACTION");
|
||||||
|
}
|
||||||
|
static td::Status ValidateZeroState(td::Slice message) {
|
||||||
|
return td::Status::Error(500, PSLICE() << "VALIDATE_ZERO_STATE: " << message);
|
||||||
|
}
|
||||||
|
static td::Status ValidateBlockProof() {
|
||||||
|
return td::Status::Error(500, "VALIDATE_BLOCK_PROOF");
|
||||||
|
}
|
||||||
|
static td::Status NoLiteServers() {
|
||||||
|
return td::Status::Error(500, "NO_LITE_SERVERS");
|
||||||
|
}
|
||||||
|
static td::Status LiteServerNetwork() {
|
||||||
|
return td::Status::Error(500, "LITE_SERVER_NETWORK");
|
||||||
|
}
|
||||||
|
static td::Status Cancelled() {
|
||||||
|
return td::Status::Error(500, "CANCELLED");
|
||||||
|
}
|
||||||
|
static td::Status NotEnoughFunds() {
|
||||||
|
return td::Status::Error(500, "NOT_ENOUGH_FUNDS");
|
||||||
|
}
|
||||||
|
|
||||||
|
static td::Status LiteServer(td::int32 code, td::Slice message) {
|
||||||
|
auto f = [&](td::Slice code_description) { return LiteServer(code, code_description, message); };
|
||||||
|
switch (ton::ErrorCode(code)) {
|
||||||
|
case ton::ErrorCode::cancelled:
|
||||||
|
return f("CANCELLED");
|
||||||
|
case ton::ErrorCode::failure:
|
||||||
|
return f("FAILURE");
|
||||||
|
case ton::ErrorCode::error:
|
||||||
|
return f("ERROR");
|
||||||
|
case ton::ErrorCode::warning:
|
||||||
|
return f("WARNING");
|
||||||
|
case ton::ErrorCode::protoviolation:
|
||||||
|
return f("PROTOVIOLATION");
|
||||||
|
case ton::ErrorCode::timeout:
|
||||||
|
return f("TIMEOUT");
|
||||||
|
case ton::ErrorCode::notready:
|
||||||
|
return f("NOTREADY");
|
||||||
|
}
|
||||||
|
return f("UNKNOWN");
|
||||||
|
}
|
||||||
|
|
||||||
|
static td::Status LiteServer(td::int32 code, td::Slice code_description, td::Slice message) {
|
||||||
|
return td::Status::Error(500, PSLICE() << "LITE_SERVER_" << code_description << ": " << message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace tonlib
|
|
@ -27,13 +27,13 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
td::Ref<vm::Cell> Wallet::get_init_state(const td::Ed25519::PublicKey& public_key) {
|
td::Ref<vm::Cell> Wallet::get_init_state(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||||
auto code = get_init_code();
|
auto code = get_init_code();
|
||||||
auto data = get_init_data(public_key);
|
auto data = get_init_data(public_key);
|
||||||
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
return GenericAccount::get_init_state(std::move(code), std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> Wallet::get_init_message(const td::Ed25519::PrivateKey& private_key) {
|
td::Ref<vm::Cell> Wallet::get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept {
|
||||||
td::uint32 seqno = 0;
|
td::uint32 seqno = 0;
|
||||||
td::uint32 valid_until = std::numeric_limits<td::uint32>::max();
|
td::uint32 valid_until = std::numeric_limits<td::uint32>::max();
|
||||||
auto signature =
|
auto signature =
|
||||||
|
@ -45,7 +45,7 @@ td::Ref<vm::Cell> Wallet::get_init_message(const td::Ed25519::PrivateKey& privat
|
||||||
|
|
||||||
td::Ref<vm::Cell> Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
td::Ref<vm::Cell> Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||||
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
||||||
const block::StdAddress& dest_address) {
|
const block::StdAddress& dest_address) noexcept {
|
||||||
td::BigInt256 dest_addr;
|
td::BigInt256 dest_addr;
|
||||||
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
dest_addr.import_bits(dest_address.addr.as_bitslice());
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
|
@ -54,11 +54,15 @@ td::Ref<vm::Cell> Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& pri
|
||||||
.append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok())
|
.append_cellslice(binary_bitstring_to_cellslice("b{000100}").move_as_ok())
|
||||||
.store_long(dest_address.workchain, 8)
|
.store_long(dest_address.workchain, 8)
|
||||||
.store_int256(dest_addr, 256);
|
.store_int256(dest_addr, 256);
|
||||||
|
td::int32 send_mode = 3;
|
||||||
|
if (gramms == -1) {
|
||||||
|
gramms = 0;
|
||||||
|
send_mode += 128;
|
||||||
|
}
|
||||||
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
block::tlb::t_Grams.store_integer_value(cb, td::BigInt256(gramms));
|
||||||
cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4);
|
cb.store_zeroes(9 + 64 + 32 + 1 + 1).store_bytes("\0\0\0\0", 4);
|
||||||
vm::CellString::store(cb, message, 35 * 8).ensure();
|
vm::CellString::store(cb, message, 35 * 8).ensure();
|
||||||
auto message_inner = cb.finalize();
|
auto message_inner = cb.finalize();
|
||||||
td::int8 send_mode = 3;
|
|
||||||
auto message_outer = vm::CellBuilder()
|
auto message_outer = vm::CellBuilder()
|
||||||
.store_long(seqno, 32)
|
.store_long(seqno, 32)
|
||||||
.store_long(valid_until, 32)
|
.store_long(valid_until, 32)
|
||||||
|
@ -70,7 +74,7 @@ td::Ref<vm::Cell> Wallet::make_a_gift_message(const td::Ed25519::PrivateKey& pri
|
||||||
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> Wallet::get_init_code() {
|
td::Ref<vm::Cell> Wallet::get_init_code() noexcept {
|
||||||
static auto res = [] {
|
static auto res = [] {
|
||||||
auto serialized_code = td::base64_decode(
|
auto serialized_code = td::base64_decode(
|
||||||
"te6ccgEEAQEAAAAAVwAAqv8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x8B+CO78mPtRNDTH9P/"
|
"te6ccgEEAQEAAAAAVwAAqv8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x8B+CO78mPtRNDTH9P/"
|
||||||
|
@ -81,11 +85,11 @@ td::Ref<vm::Cell> Wallet::get_init_code() {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm::CellHash Wallet::get_init_code_hash() {
|
vm::CellHash Wallet::get_init_code_hash() noexcept {
|
||||||
return get_init_code()->get_hash();
|
return get_init_code()->get_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Ref<vm::Cell> Wallet::get_init_data(const td::Ed25519::PublicKey& public_key) {
|
td::Ref<vm::Cell> Wallet::get_init_data(const td::Ed25519::PublicKey& public_key) noexcept {
|
||||||
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
return vm::CellBuilder().store_long(0, 32).store_bytes(public_key.as_octet_string()).finalize();
|
||||||
}
|
}
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|
|
@ -27,14 +27,14 @@ namespace tonlib {
|
||||||
class Wallet {
|
class Wallet {
|
||||||
public:
|
public:
|
||||||
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
|
||||||
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key);
|
static td::Ref<vm::Cell> get_init_state(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||||
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key);
|
static td::Ref<vm::Cell> get_init_message(const td::Ed25519::PrivateKey& private_key) noexcept;
|
||||||
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
static td::Ref<vm::Cell> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 seqno,
|
||||||
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
td::uint32 valid_until, td::int64 gramms, td::Slice message,
|
||||||
const block::StdAddress& dest_address);
|
const block::StdAddress& dest_address) noexcept;
|
||||||
|
|
||||||
static td::Ref<vm::Cell> get_init_code();
|
static td::Ref<vm::Cell> get_init_code() noexcept;
|
||||||
static vm::CellHash get_init_code_hash();
|
static vm::CellHash get_init_code_hash() noexcept;
|
||||||
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key);
|
static td::Ref<vm::Cell> get_init_data(const td::Ed25519::PublicKey& public_key) noexcept;
|
||||||
};
|
};
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
td::Result<DecryptedKey> EncryptedKey::decrypt(td::Slice local_password, bool check_public_key) {
|
td::Result<DecryptedKey> EncryptedKey::decrypt(td::Slice local_password, bool check_public_key) {
|
||||||
LOG(ERROR) << "decrypt";
|
|
||||||
if (secret.size() != 32) {
|
if (secret.size() != 32) {
|
||||||
return td::Status::Error("Failed to decrypt key: invalid secret size");
|
return td::Status::Error("Failed to decrypt key: invalid secret size");
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,7 @@ class TonlibCli : public td::actor::Actor {
|
||||||
td::TerminalIO::out() << "keys - show all stored keys\n";
|
td::TerminalIO::out() << "keys - show all stored keys\n";
|
||||||
td::TerminalIO::out() << "unpackaddress <address> - validate and parse address\n";
|
td::TerminalIO::out() << "unpackaddress <address> - validate and parse address\n";
|
||||||
td::TerminalIO::out() << "importkey - import key\n";
|
td::TerminalIO::out() << "importkey - import key\n";
|
||||||
|
td::TerminalIO::out() << "deletekeys - delete ALL PRIVATE KEYS\n";
|
||||||
td::TerminalIO::out() << "exportkey [<key_id>] - export key\n";
|
td::TerminalIO::out() << "exportkey [<key_id>] - export key\n";
|
||||||
td::TerminalIO::out() << "setconfig <path> [<name>] [<use_callback>] [<force>] - set lite server config\n";
|
td::TerminalIO::out() << "setconfig <path> [<name>] [<use_callback>] [<force>] - set lite server config\n";
|
||||||
td::TerminalIO::out() << "getstate <key_id> - get state of simple wallet with requested key\n";
|
td::TerminalIO::out() << "getstate <key_id> - get state of simple wallet with requested key\n";
|
||||||
|
@ -213,6 +214,8 @@ class TonlibCli : public td::actor::Actor {
|
||||||
try_stop();
|
try_stop();
|
||||||
} else if (cmd == "keys") {
|
} else if (cmd == "keys") {
|
||||||
dump_keys();
|
dump_keys();
|
||||||
|
} else if (cmd == "deletekeys") {
|
||||||
|
delete_all_keys();
|
||||||
} else if (cmd == "exportkey") {
|
} else if (cmd == "exportkey") {
|
||||||
export_key(parser.read_word());
|
export_key(parser.read_word());
|
||||||
} else if (cmd == "importkey") {
|
} else if (cmd == "importkey") {
|
||||||
|
@ -415,6 +418,27 @@ class TonlibCli : public td::actor::Actor {
|
||||||
dump_key(i);
|
dump_key(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void delete_all_keys() {
|
||||||
|
static td::Slice password = td::Slice("I have written down mnemonic words");
|
||||||
|
td::TerminalIO::out() << "You are going to delete ALL PRIVATE KEYS. To confirm enter `" << password << "`\n";
|
||||||
|
cont_ = [this](td::Slice entered) {
|
||||||
|
if (password == entered) {
|
||||||
|
this->do_delete_all_keys();
|
||||||
|
} else {
|
||||||
|
td::TerminalIO::out() << "Your keys left intact\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_delete_all_keys() {
|
||||||
|
send_query(tonlib_api::make_object<tonlib_api::deleteAllKeys>(), [](auto r_res) {
|
||||||
|
if (r_res.is_error()) {
|
||||||
|
td::TerminalIO::out() << "Something went wrong: " << r_res.error() << "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
td::TerminalIO::out() << "All your keys have been deleted\n";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::string key_db_path() {
|
std::string key_db_path() {
|
||||||
return options_.key_dir + TD_DIR_SLASH + "key_db";
|
return options_.key_dir + TD_DIR_SLASH + "key_db";
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
#include "td/utils/misc.h"
|
#include "td/utils/misc.h"
|
||||||
#include "vm/cellslice.h"
|
#include "vm/cellslice.h"
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
|
int VERBOSITY_NAME(tonlib_query) = VERBOSITY_NAME(INFO);
|
||||||
|
int VERBOSITY_NAME(last_block) = VERBOSITY_NAME(INFO);
|
||||||
|
int VERBOSITY_NAME(lite_server) = VERBOSITY_NAME(INFO);
|
||||||
|
|
||||||
td::Result<td::Ref<vm::CellSlice>> binary_bitstring_to_cellslice(td::Slice literal) {
|
td::Result<td::Ref<vm::CellSlice>> binary_bitstring_to_cellslice(td::Slice literal) {
|
||||||
unsigned char buff[128];
|
unsigned char buff[128];
|
||||||
if (!begins_with(literal, "b{") || !ends_with(literal, "}")) {
|
if (!begins_with(literal, "b{") || !ends_with(literal, "}")) {
|
||||||
|
|
|
@ -21,6 +21,21 @@
|
||||||
#include "ton/ton-types.h"
|
#include "ton/ton-types.h"
|
||||||
#include "block/block.h"
|
#include "block/block.h"
|
||||||
#include "block/block-parse.h"
|
#include "block/block-parse.h"
|
||||||
|
|
||||||
namespace tonlib {
|
namespace tonlib {
|
||||||
|
template <class F>
|
||||||
|
auto try_f(F&& f) noexcept -> decltype(f()) {
|
||||||
|
try {
|
||||||
|
return f();
|
||||||
|
} catch (vm::VmError error) {
|
||||||
|
return td::Status::Error(PSLICE() << "Got a vm exception: " << error.get_msg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TRY_VM(f) try_f([&] { return f; })
|
||||||
|
|
||||||
|
extern int VERBOSITY_NAME(tonlib_query);
|
||||||
|
extern int VERBOSITY_NAME(last_block);
|
||||||
|
extern int VERBOSITY_NAME(lite_server);
|
||||||
td::Result<td::Ref<vm::CellSlice>> binary_bitstring_to_cellslice(td::Slice literal);
|
td::Result<td::Ref<vm::CellSlice>> binary_bitstring_to_cellslice(td::Slice literal);
|
||||||
} // namespace tonlib
|
} // namespace tonlib
|
||||||
|
|
|
@ -473,6 +473,21 @@ struct BlockHandleImpl : public BlockHandleInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unsafe_clear_applied() override {
|
||||||
|
if (is_applied()) {
|
||||||
|
lock();
|
||||||
|
flags_ &= ~Flags::dbf_applied;
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void unsafe_clear_next() override {
|
||||||
|
if (inited_next_left() || inited_next_right()) {
|
||||||
|
lock();
|
||||||
|
flags_ &= ~(Flags::dbf_inited_next_left | Flags::dbf_inited_next_right);
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
td::BufferSlice serialize() const override;
|
td::BufferSlice serialize() const override;
|
||||||
BlockHandleImpl(BlockIdExt id)
|
BlockHandleImpl(BlockIdExt id)
|
||||||
: id_(id), flags_(id_.is_masterchain() ? static_cast<td::uint32>(dbf_masterchain) : 0) {
|
: id_(id), flags_(id_.is_masterchain() ? static_cast<td::uint32>(dbf_masterchain) : 0) {
|
||||||
|
|
|
@ -229,6 +229,73 @@ tl_object_ptr<ton_api::db_blockdb_lru> BlockDb::DbEntry::release() {
|
||||||
return create_tl_object<ton_api::db_blockdb_lru>(create_tl_block_id(block_id), prev, next);
|
return create_tl_object<ton_api::db_blockdb_lru>(create_tl_block_id(block_id), prev, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlockDb::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {
|
||||||
|
std::map<ShardIdFull, BlockSeqno> max_seqno;
|
||||||
|
max_seqno.emplace(ShardIdFull{masterchainId}, state->get_seqno() + 1);
|
||||||
|
|
||||||
|
auto shards = state->get_shards();
|
||||||
|
auto it = KeyHash::zero();
|
||||||
|
kv_->begin_transaction().ensure();
|
||||||
|
while (true) {
|
||||||
|
auto R = get_block_lru(it);
|
||||||
|
R.ensure();
|
||||||
|
auto v = R.move_as_ok();
|
||||||
|
it = v.next;
|
||||||
|
R = get_block_lru(it);
|
||||||
|
R.ensure();
|
||||||
|
v = R.move_as_ok();
|
||||||
|
if (v.is_empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = v.block_id.shard_full();
|
||||||
|
if (!max_seqno.count(s)) {
|
||||||
|
bool found = false;
|
||||||
|
for (auto &shard : shards) {
|
||||||
|
if (shard_intersects(shard->shard(), s)) {
|
||||||
|
found = true;
|
||||||
|
max_seqno.emplace(s, shard->top_block_id().seqno() + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
max_seqno.emplace(s, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool to_delete = v.block_id.seqno() >= max_seqno[s];
|
||||||
|
if (to_delete) {
|
||||||
|
auto key_hash = get_block_value_key(v.block_id);
|
||||||
|
auto B = get_block_value(key_hash);
|
||||||
|
B.ensure();
|
||||||
|
auto handleR = create_block_handle(B.move_as_ok());
|
||||||
|
handleR.ensure();
|
||||||
|
auto handle = handleR.move_as_ok();
|
||||||
|
|
||||||
|
handle->unsafe_clear_applied();
|
||||||
|
handle->unsafe_clear_next();
|
||||||
|
|
||||||
|
if (handle->need_flush()) {
|
||||||
|
set_block_value(key_hash, handle->serialize());
|
||||||
|
}
|
||||||
|
} else if (v.block_id.seqno() + 1 == max_seqno[s]) {
|
||||||
|
auto key_hash = get_block_value_key(v.block_id);
|
||||||
|
auto B = get_block_value(key_hash);
|
||||||
|
B.ensure();
|
||||||
|
auto handleR = create_block_handle(B.move_as_ok());
|
||||||
|
handleR.ensure();
|
||||||
|
auto handle = handleR.move_as_ok();
|
||||||
|
|
||||||
|
handle->unsafe_clear_next();
|
||||||
|
|
||||||
|
if (handle->need_flush()) {
|
||||||
|
set_block_value(key_hash, handle->serialize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kv_->commit_transaction().ensure();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|
|
@ -41,6 +41,8 @@ class BlockDb : public td::actor::Actor {
|
||||||
void gc();
|
void gc();
|
||||||
void skip_gc();
|
void skip_gc();
|
||||||
|
|
||||||
|
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise);
|
||||||
|
|
||||||
BlockDb(td::actor::ActorId<RootDb> root_db, std::string db_path);
|
BlockDb(td::actor::ActorId<RootDb> root_db, std::string db_path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -138,7 +138,7 @@ void FileDb::load_file(RefId ref_id, td::Promise<td::BufferSlice> promise) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), 0, -1, std::move(P)).release();
|
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), 0, -1, 0, std::move(P)).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileDb::load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size, td::Promise<td::BufferSlice> promise) {
|
void FileDb::load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size, td::Promise<td::BufferSlice> promise) {
|
||||||
|
@ -159,7 +159,7 @@ void FileDb::load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), offset, max_size, std::move(P))
|
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), offset, max_size, 0, std::move(P))
|
||||||
.release();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,25 +81,32 @@ class WriteFile : public td::actor::Actor {
|
||||||
|
|
||||||
class ReadFile : public td::actor::Actor {
|
class ReadFile : public td::actor::Actor {
|
||||||
public:
|
public:
|
||||||
|
enum Flags : td::uint32 { f_disable_log = 1 };
|
||||||
void start_up() override {
|
void start_up() override {
|
||||||
auto S = td::read_file(file_name_, max_length_, offset_);
|
auto S = td::read_file(file_name_, max_length_, offset_);
|
||||||
if (S.is_ok()) {
|
if (S.is_ok()) {
|
||||||
promise_.set_result(S.move_as_ok());
|
promise_.set_result(S.move_as_ok());
|
||||||
} else {
|
} else {
|
||||||
// TODO check error code
|
// TODO check error code
|
||||||
LOG(ERROR) << "missing file " << file_name_;
|
if (flags_ & Flags::f_disable_log) {
|
||||||
|
LOG(DEBUG) << "missing file " << file_name_;
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "missing file " << file_name_;
|
||||||
|
}
|
||||||
promise_.set_error(td::Status::Error(ErrorCode::notready, "file does not exist"));
|
promise_.set_error(td::Status::Error(ErrorCode::notready, "file does not exist"));
|
||||||
}
|
}
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
ReadFile(std::string file_name, td::int64 offset, td::int64 max_length, td::Promise<td::BufferSlice> promise)
|
ReadFile(std::string file_name, td::int64 offset, td::int64 max_length, td::uint32 flags,
|
||||||
: file_name_(file_name), offset_(offset), max_length_(max_length), promise_(std::move(promise)) {
|
td::Promise<td::BufferSlice> promise)
|
||||||
|
: file_name_(file_name), offset_(offset), max_length_(max_length), flags_(flags), promise_(std::move(promise)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string file_name_;
|
std::string file_name_;
|
||||||
td::int64 offset_;
|
td::int64 offset_;
|
||||||
td::int64 max_length_;
|
td::int64 max_length_;
|
||||||
|
td::uint32 flags_;
|
||||||
td::Promise<td::BufferSlice> promise_;
|
td::Promise<td::BufferSlice> promise_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,95 @@ void LtDb::start_up() {
|
||||||
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
|
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LtDb::truncate_workchain(ShardIdFull shard, td::Ref<MasterchainState> state) {
|
||||||
|
auto key = get_desc_key(shard);
|
||||||
|
std::string value;
|
||||||
|
auto R = kv_->get(key, value);
|
||||||
|
R.ensure();
|
||||||
|
CHECK(R.move_as_ok() == td::KeyValue::GetStatus::Ok);
|
||||||
|
auto F = fetch_tl_object<ton_api::db_lt_desc_value>(td::BufferSlice{value}, true);
|
||||||
|
F.ensure();
|
||||||
|
auto f = F.move_as_ok();
|
||||||
|
|
||||||
|
auto shards = state->get_shards();
|
||||||
|
BlockSeqno seqno = 0;
|
||||||
|
if (shard.is_masterchain()) {
|
||||||
|
seqno = state->get_seqno();
|
||||||
|
} else {
|
||||||
|
for (auto s : shards) {
|
||||||
|
if (shard_intersects(s->shard(), shard)) {
|
||||||
|
seqno = s->top_block_id().seqno();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (f->last_idx_ > f->first_idx_) {
|
||||||
|
auto db_key = get_el_key(shard, f->last_idx_ - 1);
|
||||||
|
R = kv_->get(db_key, value);
|
||||||
|
R.ensure();
|
||||||
|
CHECK(R.move_as_ok() == td::KeyValue::GetStatus::Ok);
|
||||||
|
auto E = fetch_tl_object<ton_api::db_lt_el_value>(td::BufferSlice{value}, true);
|
||||||
|
E.ensure();
|
||||||
|
auto e = E.move_as_ok();
|
||||||
|
|
||||||
|
bool to_delete = static_cast<td::uint32>(e->id_->seqno_) > seqno;
|
||||||
|
|
||||||
|
if (!to_delete) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
f->last_idx_--;
|
||||||
|
kv_->erase(db_key).ensure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->first_idx_ == f->last_idx_) {
|
||||||
|
f->last_ts_ = 0;
|
||||||
|
f->last_lt_ = 0;
|
||||||
|
f->last_seqno_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv_->set(key, serialize_tl_object(f, true)).ensure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LtDb::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {
|
||||||
|
auto status_key = create_serialize_tl_object<ton_api::db_lt_status_key>();
|
||||||
|
td::Result<td::KeyValue::GetStatus> R;
|
||||||
|
td::uint32 total_shards = 0;
|
||||||
|
{
|
||||||
|
std::string value;
|
||||||
|
R = kv_->get(status_key.as_slice(), value);
|
||||||
|
R.ensure();
|
||||||
|
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto F = fetch_tl_object<ton_api::db_lt_status_value>(value, true);
|
||||||
|
F.ensure();
|
||||||
|
auto f = F.move_as_ok();
|
||||||
|
total_shards = f->total_shards_;
|
||||||
|
if (total_shards == 0) {
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kv_->begin_transaction().ensure();
|
||||||
|
for (td::uint32 idx = 0; idx < total_shards; idx++) {
|
||||||
|
auto shard_key = create_serialize_tl_object<ton_api::db_lt_shard_key>(idx);
|
||||||
|
std::string value;
|
||||||
|
R = kv_->get(shard_key.as_slice(), value);
|
||||||
|
R.ensure();
|
||||||
|
CHECK(R.move_as_ok() == td::KeyValue::GetStatus::Ok);
|
||||||
|
auto F = fetch_tl_object<ton_api::db_lt_shard_value>(value, true);
|
||||||
|
F.ensure();
|
||||||
|
auto f = F.move_as_ok();
|
||||||
|
|
||||||
|
truncate_workchain(ShardIdFull{f->workchain_, static_cast<td::uint64>(f->shard_)}, state);
|
||||||
|
}
|
||||||
|
kv_->commit_transaction().ensure();
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "td/actor/actor.h"
|
#include "td/actor/actor.h"
|
||||||
#include "td/db/KeyValueAsync.h"
|
#include "td/db/KeyValueAsync.h"
|
||||||
|
#include "validator/interfaces/db.h"
|
||||||
|
|
||||||
#include "ton/ton-types.h"
|
#include "ton/ton-types.h"
|
||||||
|
|
||||||
|
@ -42,6 +43,9 @@ class LtDb : public td::actor::Actor {
|
||||||
void get_block_by_unix_time(AccountIdPrefixFull account_id, UnixTime ts, td::Promise<BlockIdExt> promise);
|
void get_block_by_unix_time(AccountIdPrefixFull account_id, UnixTime ts, td::Promise<BlockIdExt> promise);
|
||||||
void get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<BlockIdExt> promise);
|
void get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<BlockIdExt> promise);
|
||||||
|
|
||||||
|
void truncate_workchain(ShardIdFull shard, td::Ref<MasterchainState> state);
|
||||||
|
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise);
|
||||||
|
|
||||||
void start_up() override;
|
void start_up() override;
|
||||||
|
|
||||||
LtDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(std::move(db_path)) {
|
LtDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(std::move(db_path)) {
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "td/utils/overloaded.h"
|
#include "td/utils/overloaded.h"
|
||||||
#include "common/checksum.h"
|
#include "common/checksum.h"
|
||||||
#include "validator/stats-merger.h"
|
#include "validator/stats-merger.h"
|
||||||
|
#include "td/actor/MultiPromise.h"
|
||||||
|
|
||||||
namespace ton {
|
namespace ton {
|
||||||
|
|
||||||
|
@ -413,6 +414,14 @@ void RootDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promis
|
||||||
td::actor::send_closure(state_db_, &StateDb::get_async_serializer_state, std::move(promise));
|
td::actor::send_closure(state_db_, &StateDb::get_async_serializer_state, std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RootDb::update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise) {
|
||||||
|
td::actor::send_closure(state_db_, &StateDb::update_hardforks, std::move(blocks), std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RootDb::get_hardforks(td::Promise<std::vector<BlockIdExt>> promise) {
|
||||||
|
td::actor::send_closure(state_db_, &StateDb::get_hardforks, std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
void RootDb::start_up() {
|
void RootDb::start_up() {
|
||||||
cell_db_ = td::actor::create_actor<CellDb>("celldb", actor_id(this), root_path_ + "/celldb/");
|
cell_db_ = td::actor::create_actor<CellDb>("celldb", actor_id(this), root_path_ + "/celldb/");
|
||||||
block_db_ = td::actor::create_actor<BlockDb>("blockdb", actor_id(this), root_path_ + "/blockdb/");
|
block_db_ = td::actor::create_actor<BlockDb>("blockdb", actor_id(this), root_path_ + "/blockdb/");
|
||||||
|
@ -481,6 +490,15 @@ void RootDb::prepare_stats(td::Promise<std::vector<std::pair<std::string, std::s
|
||||||
td::actor::send_closure(archive_db_, &FileDb::prepare_stats, merger.make_promise("archivedb."));
|
td::actor::send_closure(archive_db_, &FileDb::prepare_stats, merger.make_promise("archivedb."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RootDb::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {
|
||||||
|
td::MultiPromise mp;
|
||||||
|
auto ig = mp.init_guard();
|
||||||
|
ig.add_promise(std::move(promise));
|
||||||
|
|
||||||
|
td::actor::send_closure(lt_db_, &LtDb::truncate, state, ig.get_promise());
|
||||||
|
td::actor::send_closure(block_db_, &BlockDb::truncate, state, ig.get_promise());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|
|
@ -104,6 +104,9 @@ class RootDb : public Db {
|
||||||
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
|
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
|
||||||
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) override;
|
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) override;
|
||||||
|
|
||||||
|
void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise) override;
|
||||||
|
void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise) override;
|
||||||
|
|
||||||
void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) override;
|
void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) override;
|
||||||
|
|
||||||
void allow_state_gc(BlockIdExt block_id, td::Promise<bool> promise);
|
void allow_state_gc(BlockIdExt block_id, td::Promise<bool> promise);
|
||||||
|
@ -112,6 +115,8 @@ class RootDb : public Db {
|
||||||
|
|
||||||
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override;
|
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override;
|
||||||
|
|
||||||
|
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
td::actor::ActorId<ValidatorManager> validator_manager_;
|
td::actor::ActorId<ValidatorManager> validator_manager_;
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,44 @@ void StateDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promi
|
||||||
static_cast<UnixTime>(obj->last_ts_)});
|
static_cast<UnixTime>(obj->last_ts_)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StateDb::update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise) {
|
||||||
|
auto key = create_hash_tl_object<ton_api::db_state_key_hardforks>();
|
||||||
|
|
||||||
|
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> vec;
|
||||||
|
|
||||||
|
for (auto &e : blocks) {
|
||||||
|
vec.push_back(create_tl_block_id(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
kv_->begin_transaction().ensure();
|
||||||
|
kv_->set(key.as_slice(), create_serialize_tl_object<ton_api::db_state_hardforks>(std::move(vec))).ensure();
|
||||||
|
kv_->commit_transaction();
|
||||||
|
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateDb::get_hardforks(td::Promise<std::vector<BlockIdExt>> promise) {
|
||||||
|
auto key = create_hash_tl_object<ton_api::db_state_key_hardforks>();
|
||||||
|
|
||||||
|
std::string value;
|
||||||
|
auto R = kv_->get(key.as_slice(), value);
|
||||||
|
R.ensure();
|
||||||
|
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
|
||||||
|
promise.set_value(std::vector<BlockIdExt>{});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto F = fetch_tl_object<ton_api::db_state_hardforks>(value, true);
|
||||||
|
F.ensure();
|
||||||
|
auto f = F.move_as_ok();
|
||||||
|
|
||||||
|
std::vector<BlockIdExt> vec;
|
||||||
|
for (auto &e : f->blocks_) {
|
||||||
|
vec.push_back(create_block_id(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
promise.set_value(std::move(vec));
|
||||||
|
}
|
||||||
|
|
||||||
StateDb::StateDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(db_path) {
|
StateDb::StateDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(db_path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,9 @@ class StateDb : public td::actor::Actor {
|
||||||
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise);
|
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise);
|
||||||
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise);
|
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise);
|
||||||
|
|
||||||
|
void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise);
|
||||||
|
void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise);
|
||||||
|
|
||||||
StateDb(td::actor::ActorId<RootDb> root_db, std::string path);
|
StateDb(td::actor::ActorId<RootDb> root_db, std::string path);
|
||||||
|
|
||||||
void start_up() override;
|
void start_up() override;
|
||||||
|
|
|
@ -25,7 +25,9 @@ namespace validator {
|
||||||
|
|
||||||
void StaticFilesDb::load_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) {
|
void StaticFilesDb::load_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) {
|
||||||
auto path = path_ + "/" + file_hash.to_hex();
|
auto path = path_ + "/" + file_hash.to_hex();
|
||||||
td::actor::create_actor<db::ReadFile>("read file", path, 0, -1, std::move(promise)).release();
|
td::actor::create_actor<db::ReadFile>("read file", path, 0, -1, db::ReadFile::Flags::f_disable_log,
|
||||||
|
std::move(promise))
|
||||||
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
|
@ -56,6 +56,20 @@ void WaitBlockData::start_up() {
|
||||||
alarm_timestamp() = timeout_;
|
alarm_timestamp() = timeout_;
|
||||||
|
|
||||||
CHECK(handle_);
|
CHECK(handle_);
|
||||||
|
if (!handle_->id().is_masterchain()) {
|
||||||
|
start();
|
||||||
|
} else {
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<bool> R) {
|
||||||
|
R.ensure();
|
||||||
|
auto value = R.move_as_ok();
|
||||||
|
td::actor::send_closure(SelfId, &WaitBlockData::set_is_hardfork, value);
|
||||||
|
});
|
||||||
|
td::actor::send_closure(manager_, &ValidatorManager::check_is_hardfork, handle_->id(), std::move(P));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitBlockData::set_is_hardfork(bool value) {
|
||||||
|
is_hardfork_ = value;
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +90,18 @@ void WaitBlockData::start() {
|
||||||
});
|
});
|
||||||
|
|
||||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
|
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
|
||||||
|
} else if (try_read_static_file_.is_in_past() && (is_hardfork_ || !handle_->id().is_masterchain())) {
|
||||||
|
try_read_static_file_ = td::Timestamp::in(30.0);
|
||||||
|
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
|
||||||
|
if (R.is_error()) {
|
||||||
|
td::actor::send_closure(SelfId, &WaitBlockData::start);
|
||||||
|
} else {
|
||||||
|
td::actor::send_closure(SelfId, &WaitBlockData::got_static_file, R.move_as_ok());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
td::actor::send_closure(manager_, &ValidatorManager::try_get_static_file, handle_->id().file_hash, std::move(P));
|
||||||
} else {
|
} else {
|
||||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
|
||||||
if (R.is_error()) {
|
if (R.is_error()) {
|
||||||
|
@ -149,6 +175,29 @@ void WaitBlockData::force_read_from_db() {
|
||||||
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
|
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaitBlockData::got_static_file(td::BufferSlice data) {
|
||||||
|
CHECK(td::sha256_bits256(data.as_slice()) == handle_->id().file_hash);
|
||||||
|
|
||||||
|
auto R = create_block(handle_->id(), std::move(data));
|
||||||
|
if (R.is_error()) {
|
||||||
|
LOG(ERROR) << "bad static file block: " << R.move_as_error();
|
||||||
|
start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data_ = R.move_as_ok();
|
||||||
|
|
||||||
|
CHECK(is_hardfork_ || !handle_->id().is_masterchain());
|
||||||
|
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||||
|
if (R.is_error()) {
|
||||||
|
td::actor::send_closure(SelfId, &WaitBlockData::abort_query, R.move_as_error_prefix("bad static file block: "));
|
||||||
|
} else {
|
||||||
|
td::actor::send_closure(SelfId, &WaitBlockData::finish_query);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
run_hardfork_accept_block_query(handle_->id(), data_, manager_, std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|
|
@ -51,12 +51,14 @@ class WaitBlockData : public td::actor::Actor {
|
||||||
void force_read_from_db();
|
void force_read_from_db();
|
||||||
|
|
||||||
void start_up() override;
|
void start_up() override;
|
||||||
void got_block_handle(BlockHandle handle);
|
void set_is_hardfork(bool value);
|
||||||
void start();
|
void start();
|
||||||
void got_block_data_from_db(td::Ref<BlockData> data);
|
void got_block_data_from_db(td::Ref<BlockData> data);
|
||||||
void got_block_data_from_net(ReceivedBlock data);
|
void got_block_data_from_net(ReceivedBlock data);
|
||||||
void failed_to_get_block_data_from_net(td::Status reason);
|
void failed_to_get_block_data_from_net(td::Status reason);
|
||||||
|
|
||||||
|
void got_static_file(td::BufferSlice data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BlockHandle handle_;
|
BlockHandle handle_;
|
||||||
|
|
||||||
|
@ -69,6 +71,8 @@ class WaitBlockData : public td::actor::Actor {
|
||||||
td::Ref<BlockData> data_;
|
td::Ref<BlockData> data_;
|
||||||
|
|
||||||
bool reading_from_db_ = false;
|
bool reading_from_db_ = false;
|
||||||
|
bool is_hardfork_ = false;
|
||||||
|
td::Timestamp try_read_static_file_ = td::Timestamp::now();
|
||||||
|
|
||||||
//td::PerfWarningTimer perf_timer_{"waitdata", 1.0};
|
//td::PerfWarningTimer perf_timer_{"waitdata", 1.0};
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,6 +52,8 @@ void run_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<
|
||||||
void run_fake_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
void run_fake_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
|
||||||
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager,
|
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager,
|
||||||
td::Promise<td::Unit> promise);
|
td::Promise<td::Unit> promise);
|
||||||
|
void run_hardfork_accept_block_query(BlockIdExt id, td::Ref<BlockData> data,
|
||||||
|
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise);
|
||||||
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
|
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
|
||||||
td::Timestamp timeout, td::Promise<td::Unit> promise);
|
td::Timestamp timeout, td::Promise<td::Unit> promise);
|
||||||
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,
|
||||||
|
|
|
@ -1466,26 +1466,10 @@ bool Collator::fetch_config_params() {
|
||||||
if (cell.is_null()) {
|
if (cell.is_null()) {
|
||||||
return fatal_error("cannot fetch current gas prices and limits from masterchain configuration");
|
return fatal_error("cannot fetch current gas prices and limits from masterchain configuration");
|
||||||
}
|
}
|
||||||
auto f = [self = this](const auto& r, td::uint64 spec_limit) {
|
if (!compute_phase_cfg_.parse_GasLimitsPrices(std::move(cell), storage_phase_cfg_.freeze_due_limit,
|
||||||
self->compute_phase_cfg_.gas_limit = r.gas_limit;
|
storage_phase_cfg_.delete_due_limit)) {
|
||||||
self->compute_phase_cfg_.special_gas_limit = spec_limit;
|
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
|
||||||
self->compute_phase_cfg_.gas_credit = r.gas_credit;
|
|
||||||
self->compute_phase_cfg_.gas_price = r.gas_price;
|
|
||||||
self->storage_phase_cfg_.freeze_due_limit = td::RefInt256{true, r.freeze_due_limit};
|
|
||||||
self->storage_phase_cfg_.delete_due_limit = td::RefInt256{true, r.delete_due_limit};
|
|
||||||
};
|
|
||||||
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
|
|
||||||
if (tlb::unpack_cell(cell, rec)) {
|
|
||||||
f(rec, rec.special_gas_limit);
|
|
||||||
} else {
|
|
||||||
block::gen::GasLimitsPrices::Record_gas_prices rec0;
|
|
||||||
if (tlb::unpack_cell(std::move(cell), rec0)) {
|
|
||||||
f(rec0, rec0.gas_limit);
|
|
||||||
} else {
|
|
||||||
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
compute_phase_cfg_.compute_threshold();
|
|
||||||
compute_phase_cfg_.block_rand_seed = rand_seed_;
|
compute_phase_cfg_.block_rand_seed = rand_seed_;
|
||||||
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256);
|
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256);
|
||||||
compute_phase_cfg_.global_config = config_->get_root_cell();
|
compute_phase_cfg_.global_config = config_->get_root_cell();
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "top-shard-descr.hpp"
|
#include "top-shard-descr.hpp"
|
||||||
#include "ton/ton-io.hpp"
|
#include "ton/ton-io.hpp"
|
||||||
#include "liteserver.hpp"
|
#include "liteserver.hpp"
|
||||||
|
#include "validator/fabric.h"
|
||||||
|
|
||||||
namespace ton {
|
namespace ton {
|
||||||
|
|
||||||
|
@ -131,6 +132,11 @@ void run_fake_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::ve
|
||||||
.release();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void run_hardfork_accept_block_query(BlockIdExt id, td::Ref<BlockData> data,
|
||||||
|
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise) {
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::error, "not implemented"));
|
||||||
|
}
|
||||||
|
|
||||||
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
|
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
|
||||||
td::Timestamp timeout, td::Promise<td::Unit> promise) {
|
td::Timestamp timeout, td::Promise<td::Unit> promise) {
|
||||||
td::actor::create_actor<ApplyBlock>(PSTRING() << "apply " << id, id, std::move(block), manager, timeout,
|
td::actor::create_actor<ApplyBlock>(PSTRING() << "apply " << id, id, std::move(block), manager, timeout,
|
||||||
|
|
|
@ -192,7 +192,7 @@ void LiteQuery::perform_getMasterchainInfo(int mode) {
|
||||||
}
|
}
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
||||||
[ Self = actor_id(this), mode ](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) {
|
[Self = actor_id(this), mode](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,7 +230,7 @@ void LiteQuery::perform_getBlock(BlockIdExt blkid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::BlockData>> res) {
|
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::BlockData>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
|
@ -256,7 +256,7 @@ void LiteQuery::perform_getBlockHeader(BlockIdExt blkid, int mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid, mode ](td::Result<Ref<ton::validator::BlockData>> res) {
|
[Self = actor_id(this), blkid, mode](td::Result<Ref<ton::validator::BlockData>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
|
@ -371,7 +371,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
|
||||||
}
|
}
|
||||||
if (blkid.id.seqno) {
|
if (blkid.id.seqno) {
|
||||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::ShardState>> res) {
|
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::ShardState>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
|
@ -381,7 +381,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid,
|
td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
|
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
|
@ -440,7 +440,7 @@ bool LiteQuery::request_mc_block_data(BlockIdExt blkid) {
|
||||||
++pending_;
|
++pending_;
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
|
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||||
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
|
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
|
||||||
|
@ -466,7 +466,7 @@ bool LiteQuery::request_mc_proof(BlockIdExt blkid, int mode) {
|
||||||
++pending_;
|
++pending_;
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ValidatorManager::get_block_proof_from_db_short, blkid,
|
manager_, &ValidatorManager::get_block_proof_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid, mode ](td::Result<Ref<Proof>> res) {
|
[Self = actor_id(this), blkid, mode](td::Result<Ref<Proof>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||||
res.move_as_error_prefix("cannot load proof for "s + blkid.to_str() + " : "));
|
res.move_as_error_prefix("cannot load proof for "s + blkid.to_str() + " : "));
|
||||||
|
@ -488,7 +488,7 @@ bool LiteQuery::request_mc_block_state(BlockIdExt blkid) {
|
||||||
++pending_;
|
++pending_;
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
|
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||||
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
|
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
|
||||||
|
@ -519,7 +519,7 @@ bool LiteQuery::request_block_state(BlockIdExt blkid) {
|
||||||
++pending_;
|
++pending_;
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
|
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||||
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
|
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
|
||||||
|
@ -541,7 +541,7 @@ bool LiteQuery::request_block_data(BlockIdExt blkid) {
|
||||||
++pending_;
|
++pending_;
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
|
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||||
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
|
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
|
||||||
|
@ -563,7 +563,7 @@ bool LiteQuery::request_proof_link(BlockIdExt blkid) {
|
||||||
++pending_;
|
++pending_;
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid,
|
manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<Ref<ProofLink>> res) {
|
[Self = actor_id(this), blkid](td::Result<Ref<ProofLink>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||||
res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : "));
|
res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : "));
|
||||||
|
@ -588,7 +588,7 @@ bool LiteQuery::request_zero_state(BlockIdExt blkid) {
|
||||||
++pending_;
|
++pending_;
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ValidatorManager::get_zero_state, blkid,
|
manager_, &ValidatorManager::get_zero_state, blkid,
|
||||||
[ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
|
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
td::actor::send_closure(Self, &LiteQuery::abort_query,
|
||||||
res.move_as_error_prefix("cannot load zerostate of "s + blkid.to_str() + " : "));
|
res.move_as_error_prefix("cannot load zerostate of "s + blkid.to_str() + " : "));
|
||||||
|
@ -632,7 +632,7 @@ void LiteQuery::perform_getAccountState(BlockIdExt blkid, WorkchainId workchain,
|
||||||
LOG(INFO) << "sending a get_top_masterchain_state_block query to manager";
|
LOG(INFO) << "sending a get_top_masterchain_state_block query to manager";
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
||||||
[Self = actor_id(this)](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res)->void {
|
[Self = actor_id(this)](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) -> void {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
|
@ -1067,7 +1067,7 @@ void LiteQuery::continue_getTransactions(unsigned remaining, bool exact) {
|
||||||
<< " " << trans_lt_;
|
<< " " << trans_lt_;
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ValidatorManager::get_block_by_lt_from_db, ton::extract_addr_prefix(acc_workchain_, acc_addr_),
|
manager_, &ValidatorManager::get_block_by_lt_from_db, ton::extract_addr_prefix(acc_workchain_, acc_addr_),
|
||||||
trans_lt_, [ Self = actor_id(this), remaining, manager = manager_ ](td::Result<BlockIdExt> res) {
|
trans_lt_, [Self = actor_id(this), remaining, manager = manager_](td::Result<BlockIdExt> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_getTransactions, res.move_as_error(), ton::BlockIdExt{});
|
td::actor::send_closure(Self, &LiteQuery::abort_getTransactions, res.move_as_error(), ton::BlockIdExt{});
|
||||||
} else {
|
} else {
|
||||||
|
@ -1141,7 +1141,7 @@ void LiteQuery::perform_getShardInfo(BlockIdExt blkid, ShardIdFull shard, bool e
|
||||||
void LiteQuery::perform_getConfigParams(BlockIdExt blkid, int mode, std::vector<int> param_list) {
|
void LiteQuery::perform_getConfigParams(BlockIdExt blkid, int mode, std::vector<int> param_list) {
|
||||||
LOG(INFO) << "started a getConfigParams(" << blkid.to_str() << ", " << mode << ", <list of " << param_list.size()
|
LOG(INFO) << "started a getConfigParams(" << blkid.to_str() << ", " << mode << ", <list of " << param_list.size()
|
||||||
<< " parameters>) liteserver query";
|
<< " parameters>) liteserver query";
|
||||||
set_continuation([ this, mode, param_list = std::move(param_list) ]() mutable {
|
set_continuation([this, mode, param_list = std::move(param_list)]() mutable {
|
||||||
continue_getConfigParams(mode, std::move(param_list));
|
continue_getConfigParams(mode, std::move(param_list));
|
||||||
});
|
});
|
||||||
request_mc_block_data_state(blkid);
|
request_mc_block_data_state(blkid);
|
||||||
|
@ -1294,7 +1294,7 @@ void LiteQuery::perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, Uni
|
||||||
LOG(INFO) << "performing a lookupBlock(" << blkid.to_str() << ", " << mode << ", " << lt << ", " << utime
|
LOG(INFO) << "performing a lookupBlock(" << blkid.to_str() << ", " << mode << ", " << lt << ", " << utime
|
||||||
<< ") query";
|
<< ") query";
|
||||||
auto P = td::PromiseCreator::lambda(
|
auto P = td::PromiseCreator::lambda(
|
||||||
[ Self = actor_id(this), manager = manager_, mode = (mode >> 4) ](td::Result<BlockIdExt> res) {
|
[Self = actor_id(this), manager = manager_, mode = (mode >> 4)](td::Result<BlockIdExt> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
|
@ -1445,10 +1445,21 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
||||||
fatal_error("destination block "s + to.to_str() + " is not a valid masterchain block id");
|
fatal_error("destination block "s + to.to_str() + " is not a valid masterchain block id");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(mode & 1)) {
|
if (mode & 1) {
|
||||||
|
base_blk_id_ = (from.seqno() > to.seqno()) ? from : to;
|
||||||
|
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, base_blk_id_,
|
||||||
|
[Self = actor_id(this), from, to, mode](td::Result<Ref<ShardState>> res) {
|
||||||
|
if (res.is_error()) {
|
||||||
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
|
} else {
|
||||||
|
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, to,
|
||||||
|
mode, Ref<MasterchainStateQ>(res.move_as_ok()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (mode & 2) {
|
||||||
td::actor::send_closure_later(
|
td::actor::send_closure_later(
|
||||||
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
|
||||||
[ Self = actor_id(this), from, mode ](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res)->void {
|
[Self = actor_id(this), from, mode](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
|
@ -1458,14 +1469,13 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
base_blk_id_ = (from.seqno() > to.seqno()) ? from : to;
|
td::actor::send_closure_later(manager_, &ton::validator::ValidatorManager::get_shard_client_state, false,
|
||||||
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, base_blk_id_,
|
[Self = actor_id(this), from, mode](td::Result<BlockIdExt> res) {
|
||||||
[ Self = actor_id(this), from, to, mode ](td::Result<Ref<ShardState>> res) {
|
|
||||||
if (res.is_error()) {
|
if (res.is_error()) {
|
||||||
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
|
||||||
} else {
|
} else {
|
||||||
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, to,
|
td::actor::send_closure_later(Self, &LiteQuery::perform_getBlockProof, from,
|
||||||
mode, Ref<MasterchainStateQ>(res.move_as_ok()));
|
res.move_as_ok(), mode | 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -734,26 +734,10 @@ bool ValidateQuery::fetch_config_params() {
|
||||||
if (cell.is_null()) {
|
if (cell.is_null()) {
|
||||||
return fatal_error("cannot fetch current gas prices and limits from masterchain configuration");
|
return fatal_error("cannot fetch current gas prices and limits from masterchain configuration");
|
||||||
}
|
}
|
||||||
auto f = [self = this](const auto& r, td::uint64 spec_limit) {
|
if (!compute_phase_cfg_.parse_GasLimitsPrices(std::move(cell), storage_phase_cfg_.freeze_due_limit,
|
||||||
self->compute_phase_cfg_.gas_limit = r.gas_limit;
|
storage_phase_cfg_.delete_due_limit)) {
|
||||||
self->compute_phase_cfg_.special_gas_limit = spec_limit;
|
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
|
||||||
self->compute_phase_cfg_.gas_credit = r.gas_credit;
|
|
||||||
self->compute_phase_cfg_.gas_price = r.gas_price;
|
|
||||||
self->storage_phase_cfg_.freeze_due_limit = td::RefInt256{true, r.freeze_due_limit};
|
|
||||||
self->storage_phase_cfg_.delete_due_limit = td::RefInt256{true, r.delete_due_limit};
|
|
||||||
};
|
|
||||||
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
|
|
||||||
if (tlb::unpack_cell(cell, rec)) {
|
|
||||||
f(rec, rec.special_gas_limit);
|
|
||||||
} else {
|
|
||||||
block::gen::GasLimitsPrices::Record_gas_prices rec0;
|
|
||||||
if (tlb::unpack_cell(std::move(cell), rec0)) {
|
|
||||||
f(rec0, rec0.gas_limit);
|
|
||||||
} else {
|
|
||||||
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
compute_phase_cfg_.compute_threshold();
|
|
||||||
compute_phase_cfg_.block_rand_seed = rand_seed_;
|
compute_phase_cfg_.block_rand_seed = rand_seed_;
|
||||||
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256);
|
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256);
|
||||||
compute_phase_cfg_.global_config = config_->get_root_cell();
|
compute_phase_cfg_.global_config = config_->get_root_cell();
|
||||||
|
@ -5227,7 +5211,7 @@ bool ValidateQuery::check_block_create_stats() {
|
||||||
auto key = td::Bits256::zero();
|
auto key = td::Bits256::zero();
|
||||||
auto old_val = ps_.block_create_stats_->lookup(key);
|
auto old_val = ps_.block_create_stats_->lookup(key);
|
||||||
auto new_val = ns_.block_create_stats_->lookup(key);
|
auto new_val = ns_.block_create_stats_->lookup(key);
|
||||||
if (new_val.is_null()) {
|
if (new_val.is_null() && (!created_by_.is_zero() || block_create_total_)) {
|
||||||
return reject_query(
|
return reject_query(
|
||||||
"new masterchain state does not contain a BlockCreator entry with zero key with total statistics");
|
"new masterchain state does not contain a BlockCreator entry with zero key with total statistics");
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,9 @@ struct BlockHandleInterface {
|
||||||
virtual void set_archived() = 0;
|
virtual void set_archived() = 0;
|
||||||
virtual void set_applied() = 0;
|
virtual void set_applied() = 0;
|
||||||
|
|
||||||
|
virtual void unsafe_clear_applied() = 0;
|
||||||
|
virtual void unsafe_clear_next() = 0;
|
||||||
|
|
||||||
virtual td::BufferSlice serialize() const = 0;
|
virtual td::BufferSlice serialize() const = 0;
|
||||||
|
|
||||||
virtual ~BlockHandleInterface() = default;
|
virtual ~BlockHandleInterface() = default;
|
||||||
|
|
|
@ -92,9 +92,14 @@ class Db : public td::actor::Actor {
|
||||||
virtual void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) = 0;
|
virtual void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) = 0;
|
||||||
virtual void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) = 0;
|
virtual void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) = 0;
|
||||||
|
|
||||||
|
virtual void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise) = 0;
|
||||||
|
virtual void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise) = 0;
|
||||||
|
|
||||||
virtual void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) = 0;
|
virtual void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) = 0;
|
||||||
|
|
||||||
virtual void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) = 0;
|
virtual void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) = 0;
|
||||||
|
|
||||||
|
virtual void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
|
@ -128,7 +128,7 @@ class ValidatorManager : public ValidatorManagerInterface {
|
||||||
virtual void send_block_broadcast(BlockBroadcast broadcast) = 0;
|
virtual void send_block_broadcast(BlockBroadcast broadcast) = 0;
|
||||||
|
|
||||||
virtual void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) = 0;
|
virtual void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) = 0;
|
||||||
virtual void get_shard_client_state(td::Promise<BlockIdExt> promise) = 0;
|
virtual void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) = 0;
|
||||||
virtual void subscribe_to_shard(ShardIdFull shard) = 0;
|
virtual void subscribe_to_shard(ShardIdFull shard) = 0;
|
||||||
|
|
||||||
virtual void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) = 0;
|
virtual void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) = 0;
|
||||||
|
@ -153,6 +153,12 @@ class ValidatorManager : public ValidatorManagerInterface {
|
||||||
virtual void update_last_known_key_block(BlockHandle handle, bool send_request) = 0;
|
virtual void update_last_known_key_block(BlockHandle handle, bool send_request) = 0;
|
||||||
virtual void update_gc_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
virtual void update_gc_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
||||||
|
|
||||||
|
virtual void update_shard_client_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
||||||
|
|
||||||
|
virtual void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) = 0;
|
||||||
|
|
||||||
|
virtual void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) = 0;
|
||||||
|
|
||||||
static bool is_persistent_state(UnixTime ts, UnixTime prev_ts) {
|
static bool is_persistent_state(UnixTime ts, UnixTime prev_ts) {
|
||||||
return ts / 1024 != prev_ts / 1024;
|
return ts / 1024 != prev_ts / 1024;
|
||||||
}
|
}
|
||||||
|
|
|
@ -897,7 +897,7 @@ void ValidatorManagerImpl::update_shard_client_state(BlockIdExt masterchain_bloc
|
||||||
td::actor::send_closure(db_, &Db::update_shard_client_state, masterchain_block_id, std::move(promise));
|
td::actor::send_closure(db_, &Db::update_shard_client_state, masterchain_block_id, std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::get_shard_client_state(td::Promise<BlockIdExt> promise) {
|
void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) {
|
||||||
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
|
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
||||||
void get_shard_client_state(td::Promise<BlockIdExt> promise) override;
|
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
|
||||||
void subscribe_to_shard(ShardIdFull shard) override {
|
void subscribe_to_shard(ShardIdFull shard) override {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,11 +329,20 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
}
|
}
|
||||||
void update_last_known_key_block(BlockHandle handle, bool send_request) override {
|
void update_last_known_key_block(BlockHandle handle, bool send_request) override {
|
||||||
}
|
}
|
||||||
|
void update_shard_client_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override {
|
||||||
|
}
|
||||||
|
|
||||||
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override {
|
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) override {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) override {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PublicKeyHash local_id_;
|
PublicKeyHash local_id_;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "adnl/utils.hpp"
|
#include "adnl/utils.hpp"
|
||||||
#include "validator/downloaders/download-state.hpp"
|
#include "validator/downloaders/download-state.hpp"
|
||||||
#include "common/delay.h"
|
#include "common/delay.h"
|
||||||
|
#include "td/actor/MultiPromise.h"
|
||||||
|
|
||||||
namespace ton {
|
namespace ton {
|
||||||
|
|
||||||
|
@ -33,7 +34,16 @@ namespace validator {
|
||||||
void ValidatorManagerMasterchainReiniter::start_up() {
|
void ValidatorManagerMasterchainReiniter::start_up() {
|
||||||
CHECK(block_id_.is_masterchain());
|
CHECK(block_id_.is_masterchain());
|
||||||
CHECK(block_id_.id.shard == shardIdAll);
|
CHECK(block_id_.id.shard == shardIdAll);
|
||||||
|
CHECK(block_id_.seqno() >= opts_->get_last_fork_masterchain_seqno());
|
||||||
|
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::written_hardforks);
|
||||||
|
});
|
||||||
|
td::actor::send_closure(db_, &Db::update_hardforks, opts_->get_hardforks(), std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainReiniter::written_hardforks() {
|
||||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||||
R.ensure();
|
R.ensure();
|
||||||
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::got_masterchain_handle, R.move_as_ok());
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::got_masterchain_handle, R.move_as_ok());
|
||||||
|
@ -268,7 +278,7 @@ void ValidatorManagerMasterchainStarter::start_up() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerMasterchainStarter::failed_to_get_init_block_id() {
|
void ValidatorManagerMasterchainStarter::failed_to_get_init_block_id() {
|
||||||
td::actor::create_actor<ValidatorManagerMasterchainReiniter>("reiniter", opts_, manager_, std::move(promise_))
|
td::actor::create_actor<ValidatorManagerMasterchainReiniter>("reiniter", opts_, manager_, db_, std::move(promise_))
|
||||||
.release();
|
.release();
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
@ -351,7 +361,7 @@ void ValidatorManagerMasterchainStarter::got_gc_block_state(td::Ref<MasterchainS
|
||||||
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_shard_block_id, R.move_as_ok());
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_shard_block_id, R.move_as_ok());
|
||||||
});
|
});
|
||||||
|
|
||||||
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, std::move(P));
|
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, true, std::move(P));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,15 +385,169 @@ void ValidatorManagerMasterchainStarter::got_key_block_handle(BlockHandle handle
|
||||||
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_shard_block_id, R.move_as_ok());
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_shard_block_id, R.move_as_ok());
|
||||||
});
|
});
|
||||||
|
|
||||||
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, std::move(P));
|
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, true, std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerMasterchainStarter::got_shard_block_id(BlockIdExt block_id) {
|
void ValidatorManagerMasterchainStarter::got_shard_block_id(BlockIdExt block_id) {
|
||||||
client_ = td::actor::create_actor<ShardClient>("shardclient", opts_, manager_);
|
client_block_id_ = block_id;
|
||||||
finish();
|
finish();
|
||||||
|
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::vector<BlockIdExt>> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_hardforks, R.move_as_ok());
|
||||||
|
});
|
||||||
|
td::actor::send_closure(db_, &Db::get_hardforks, std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainStarter::got_hardforks(std::vector<BlockIdExt> vec) {
|
||||||
|
auto h = opts_->get_hardforks();
|
||||||
|
if (h.size() < vec.size()) {
|
||||||
|
LOG(FATAL) << "cannot start: number of hardforks decreased";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (h.size() == vec.size()) {
|
||||||
|
if (h.size() > 0) {
|
||||||
|
if (*h.rbegin() != *vec.rbegin()) {
|
||||||
|
LOG(FATAL) << "cannot start: hardforks list changed";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (h.size() > vec.size() + 1) {
|
||||||
|
LOG(FATAL) << "cannot start: number of hardforks increase is too big";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto b = *h.rbegin();
|
||||||
|
if (b.seqno() > handle_->id().seqno()) {
|
||||||
|
truncated();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (b.seqno() <= gc_handle_->id().seqno()) {
|
||||||
|
LOG(FATAL) << "cannot start: new hardfork is on too old block (already gc'd)";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockIdExt id;
|
||||||
|
if (state_->get_old_mc_block_id(b.seqno() - 1, id)) {
|
||||||
|
got_truncate_block_id(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockIdExt> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_truncate_block_id, R.move_as_ok());
|
||||||
|
});
|
||||||
|
td::actor::send_closure(db_, &Db::get_block_by_seqno, AccountIdPrefixFull{masterchainId, 0}, b.seqno() - 1,
|
||||||
|
std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainStarter::got_truncate_block_id(BlockIdExt block_id) {
|
||||||
|
block_id_ = block_id;
|
||||||
|
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_truncate_block_handle, R.move_as_ok());
|
||||||
|
});
|
||||||
|
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, block_id_, false, std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainStarter::got_truncate_block_handle(BlockHandle handle) {
|
||||||
|
handle_ = std::move(handle);
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_truncate_state,
|
||||||
|
td::Ref<MasterchainState>{R.move_as_ok()});
|
||||||
|
});
|
||||||
|
td::actor::send_closure(db_, &Db::get_block_state, handle_, std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainStarter::got_truncate_state(td::Ref<MasterchainState> state) {
|
||||||
|
state_ = std::move(state);
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::truncated_db);
|
||||||
|
});
|
||||||
|
td::actor::send_closure(manager_, &ValidatorManager::truncate, state_, std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainStarter::truncated_db() {
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::truncated);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto key = state_->last_key_block_id();
|
||||||
|
|
||||||
|
td::MultiPromise mp;
|
||||||
|
auto ig = mp.init_guard();
|
||||||
|
ig.add_promise(std::move(P));
|
||||||
|
|
||||||
|
td::actor::send_closure(db_, &Db::update_init_masterchain_block, block_id_, ig.get_promise());
|
||||||
|
|
||||||
|
if (client_block_id_.seqno() > block_id_.seqno()) {
|
||||||
|
client_block_id_ = block_id_;
|
||||||
|
td::actor::send_closure(db_, &Db::update_shard_client_state, client_block_id_, ig.get_promise());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_key_block_handle_->id().seqno() > key.seqno()) {
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this),
|
||||||
|
promise = ig.get_promise()](td::Result<BlockHandle> R) mutable {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_prev_key_block_handle, R.move_as_ok());
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
});
|
||||||
|
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, key, false, std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto P = td::PromiseCreator::lambda(
|
||||||
|
[b = block_id_, key, db = db_, promise = ig.get_promise()](td::Result<AsyncSerializerState> R) mutable {
|
||||||
|
if (R.is_error()) {
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto s = R.move_as_ok();
|
||||||
|
if (s.last_block_id.seqno() <= b.seqno()) {
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.last_block_id = b;
|
||||||
|
if (s.last_written_block_id.seqno() > b.seqno()) {
|
||||||
|
s.last_written_block_id = key;
|
||||||
|
s.last_written_block_ts = 0; // may lead to extra state snapshot on disk. Does not seem like a problem
|
||||||
|
}
|
||||||
|
td::actor::send_closure(db, &Db::update_async_serializer_state, s, std::move(promise));
|
||||||
|
});
|
||||||
|
td::actor::send_closure(db_, &Db::get_async_serializer_state, std::move(P));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainStarter::got_prev_key_block_handle(BlockHandle handle) {
|
||||||
|
last_key_block_handle_ = std::move(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainStarter::truncated() {
|
||||||
|
handle_->set_next(*opts_->get_hardforks().rbegin());
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::written_next);
|
||||||
|
});
|
||||||
|
handle_->flush(manager_, handle_, std::move(P));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerMasterchainStarter::written_next() {
|
||||||
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
|
||||||
|
R.ensure();
|
||||||
|
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::finish);
|
||||||
|
});
|
||||||
|
td::actor::send_closure(db_, &Db::update_hardforks, opts_->get_hardforks(), std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerMasterchainStarter::finish() {
|
void ValidatorManagerMasterchainStarter::finish() {
|
||||||
|
client_ = td::actor::create_actor<ShardClient>("shardclient", opts_, manager_);
|
||||||
promise_.set_value(
|
promise_.set_value(
|
||||||
ValidatorManagerInitResult{handle_, state_, std::move(client_), gc_handle_, gc_state_, last_key_block_handle_});
|
ValidatorManagerInitResult{handle_, state_, std::move(client_), gc_handle_, gc_state_, last_key_block_handle_});
|
||||||
stop();
|
stop();
|
||||||
|
|
|
@ -34,12 +34,13 @@ namespace validator {
|
||||||
class ValidatorManagerMasterchainReiniter : public td::actor::Actor {
|
class ValidatorManagerMasterchainReiniter : public td::actor::Actor {
|
||||||
public:
|
public:
|
||||||
ValidatorManagerMasterchainReiniter(td::Ref<ValidatorManagerOptions> opts,
|
ValidatorManagerMasterchainReiniter(td::Ref<ValidatorManagerOptions> opts,
|
||||||
td::actor::ActorId<ValidatorManager> manager,
|
td::actor::ActorId<ValidatorManager> manager, td::actor::ActorId<Db> db,
|
||||||
td::Promise<ValidatorManagerInitResult> promise)
|
td::Promise<ValidatorManagerInitResult> promise)
|
||||||
: opts_(std::move(opts)), manager_(manager), promise_(std::move(promise)) {
|
: opts_(std::move(opts)), manager_(manager), db_(db), promise_(std::move(promise)) {
|
||||||
block_id_ = opts_->init_block_id();
|
block_id_ = opts_->init_block_id();
|
||||||
}
|
}
|
||||||
void start_up() override;
|
void start_up() override;
|
||||||
|
void written_hardforks();
|
||||||
void got_masterchain_handle(BlockHandle handle);
|
void got_masterchain_handle(BlockHandle handle);
|
||||||
void download_proof_link();
|
void download_proof_link();
|
||||||
void downloaded_proof_link(td::BufferSlice data);
|
void downloaded_proof_link(td::BufferSlice data);
|
||||||
|
@ -70,6 +71,7 @@ class ValidatorManagerMasterchainReiniter : public td::actor::Actor {
|
||||||
std::vector<ShardIdFull> shards_;
|
std::vector<ShardIdFull> shards_;
|
||||||
|
|
||||||
td::actor::ActorId<ValidatorManager> manager_;
|
td::actor::ActorId<ValidatorManager> manager_;
|
||||||
|
td::actor::ActorId<Db> db_;
|
||||||
|
|
||||||
td::Promise<ValidatorManagerInitResult> promise_;
|
td::Promise<ValidatorManagerInitResult> promise_;
|
||||||
|
|
||||||
|
@ -95,6 +97,14 @@ class ValidatorManagerMasterchainStarter : public td::actor::Actor {
|
||||||
void got_gc_block_state(td::Ref<MasterchainState> state);
|
void got_gc_block_state(td::Ref<MasterchainState> state);
|
||||||
void got_key_block_handle(BlockHandle handle);
|
void got_key_block_handle(BlockHandle handle);
|
||||||
void got_shard_block_id(BlockIdExt block_id);
|
void got_shard_block_id(BlockIdExt block_id);
|
||||||
|
void got_hardforks(std::vector<BlockIdExt> hardforks);
|
||||||
|
void got_truncate_block_id(BlockIdExt block_id);
|
||||||
|
void got_truncate_block_handle(BlockHandle handle);
|
||||||
|
void got_truncate_state(td::Ref<MasterchainState> state);
|
||||||
|
void truncated_db();
|
||||||
|
void got_prev_key_block_handle(BlockHandle handle);
|
||||||
|
void truncated();
|
||||||
|
void written_next();
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -112,6 +122,7 @@ class ValidatorManagerMasterchainStarter : public td::actor::Actor {
|
||||||
|
|
||||||
td::Promise<ValidatorManagerInitResult> promise_;
|
td::Promise<ValidatorManagerInitResult> promise_;
|
||||||
|
|
||||||
|
BlockIdExt client_block_id_;
|
||||||
td::actor::ActorOwn<ShardClient> client_;
|
td::actor::ActorOwn<ShardClient> client_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -52,29 +52,52 @@ void ValidatorManagerImpl::validate_block_is_next_proof(BlockIdExt prev_block_id
|
||||||
td::Status::Error(ErrorCode::protoviolation, "validate_block_is_next_proof() can only work for masterchain"));
|
td::Status::Error(ErrorCode::protoviolation, "validate_block_is_next_proof() can only work for masterchain"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (prev_block_id.seqno() + 1 != next_block_id.seqno()) {
|
||||||
|
VLOG(VALIDATOR_NOTICE) << "prev=" << prev_block_id << " next=" << next_block_id;
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "validate_block_is_next_proof(): bad seqno"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CHECK(last_masterchain_state_.not_null());
|
||||||
auto pp = create_proof(next_block_id, std::move(proof));
|
auto pp = create_proof(next_block_id, std::move(proof));
|
||||||
if (pp.is_error()) {
|
if (pp.is_error()) {
|
||||||
promise.set_error(pp.move_as_error_prefix("failed to create proof: "));
|
promise.set_error(pp.move_as_error_prefix("failed to create proof: "));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto P =
|
if (last_masterchain_seqno_ == prev_block_id.seqno()) {
|
||||||
td::PromiseCreator::lambda([promise = std::move(promise), id = prev_block_id](td::Result<BlockHandle> R) mutable {
|
CHECK(last_masterchain_block_id_ == prev_block_id);
|
||||||
if (R.is_error()) {
|
|
||||||
promise.set_error(R.move_as_error());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto handle = R.move_as_ok();
|
|
||||||
CHECK(!handle->merge_before());
|
|
||||||
if (handle->one_prev(true) != id) {
|
|
||||||
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "prev block mismatch"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
promise.set_value(td::Unit());
|
|
||||||
});
|
|
||||||
|
|
||||||
run_check_proof_query(next_block_id, pp.move_as_ok(), actor_id(this), td::Timestamp::in(2.0), std::move(P),
|
auto P = td::PromiseCreator::lambda(
|
||||||
opts_->is_hardfork(next_block_id));
|
[promise = std::move(promise), id = prev_block_id](td::Result<BlockHandle> R) mutable {
|
||||||
|
if (R.is_error()) {
|
||||||
|
promise.set_error(R.move_as_error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto handle = R.move_as_ok();
|
||||||
|
CHECK(!handle->merge_before());
|
||||||
|
if (handle->one_prev(true) != id) {
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "prev block mismatch"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
});
|
||||||
|
|
||||||
|
run_check_proof_query(next_block_id, pp.move_as_ok(), actor_id(this), td::Timestamp::in(2.0), std::move(P),
|
||||||
|
last_masterchain_state_, opts_->is_hardfork(next_block_id));
|
||||||
|
} else {
|
||||||
|
auto P =
|
||||||
|
td::PromiseCreator::lambda([promise = std::move(promise), next_block_id](td::Result<BlockHandle> R) mutable {
|
||||||
|
R.ensure();
|
||||||
|
auto handle = R.move_as_ok();
|
||||||
|
CHECK(handle->inited_next_left());
|
||||||
|
if (handle->one_next(true) == next_block_id) {
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
} else {
|
||||||
|
promise.set_error(td::Status::Error("next block id mismatch"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
get_block_handle(prev_block_id, false, std::move(P));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::validate_block_proof(BlockIdExt block_id, td::BufferSlice proof,
|
void ValidatorManagerImpl::validate_block_proof(BlockIdExt block_id, td::BufferSlice proof,
|
||||||
|
@ -468,7 +491,27 @@ void ValidatorManagerImpl::run_ext_query(td::BufferSlice data, td::Promise<td::B
|
||||||
promise.set_value(std::move(data));
|
promise.set_value(std::move(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
run_liteserver_query(std::move(data), actor_id(this), lite_server_cache_.get(), std::move(P));
|
auto E = fetch_tl_prefix<lite_api::liteServer_waitMasterchainSeqno>(data, true);
|
||||||
|
if (E.is_error()) {
|
||||||
|
run_liteserver_query(std::move(data), actor_id(this), lite_server_cache_.get(), std::move(P));
|
||||||
|
} else {
|
||||||
|
auto e = E.move_as_ok();
|
||||||
|
if (static_cast<BlockSeqno>(e->seqno_) <= min_confirmed_masterchain_seqno_) {
|
||||||
|
run_liteserver_query(std::move(data), actor_id(this), lite_server_cache_.get(), std::move(P));
|
||||||
|
} else {
|
||||||
|
auto t = e->timeout_ms_ < 10000 ? e->timeout_ms_ * 0.001 : 10.0;
|
||||||
|
auto Q =
|
||||||
|
td::PromiseCreator::lambda([data = std::move(data), SelfId = actor_id(this), cache = lite_server_cache_.get(),
|
||||||
|
promise = std::move(P)](td::Result<td::Unit> R) mutable {
|
||||||
|
if (R.is_error()) {
|
||||||
|
promise.set_error(R.move_as_error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
run_liteserver_query(std::move(data), SelfId, cache, std::move(promise));
|
||||||
|
});
|
||||||
|
wait_shard_client_state(e->seqno_, td::Timestamp::in(t), std::move(Q));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
|
void ValidatorManagerImpl::wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
|
||||||
|
@ -1387,7 +1430,8 @@ void ValidatorManagerImpl::new_masterchain_block() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::update_shards() {
|
void ValidatorManagerImpl::update_shards() {
|
||||||
if (last_masterchain_state_->rotated_all_shards() || last_masterchain_seqno_ == 0) {
|
if ((last_masterchain_state_->rotated_all_shards() || last_masterchain_seqno_ == 0) &&
|
||||||
|
opts_->get_last_fork_masterchain_seqno() <= last_masterchain_seqno_) {
|
||||||
allow_validate_ = true;
|
allow_validate_ = true;
|
||||||
}
|
}
|
||||||
auto exp_vec = last_masterchain_state_->get_shards();
|
auto exp_vec = last_masterchain_state_->get_shards();
|
||||||
|
@ -1468,7 +1512,7 @@ void ValidatorManagerImpl::update_shards() {
|
||||||
auto val_set = last_masterchain_state_->get_validator_set(shard);
|
auto val_set = last_masterchain_state_->get_validator_set(shard);
|
||||||
auto x = val_set->export_vector();
|
auto x = val_set->export_vector();
|
||||||
|
|
||||||
auto validator_id = get_validator(val_set);
|
auto validator_id = get_validator(shard, val_set);
|
||||||
|
|
||||||
if (!validator_id.is_zero()) {
|
if (!validator_id.is_zero()) {
|
||||||
auto val_group_id = get_validator_set_id(shard, val_set, opts_hash);
|
auto val_group_id = get_validator_set_id(shard, val_set, opts_hash);
|
||||||
|
@ -1499,7 +1543,7 @@ void ValidatorManagerImpl::update_shards() {
|
||||||
for (auto &shard : future_shards) {
|
for (auto &shard : future_shards) {
|
||||||
auto val_set = last_masterchain_state_->get_next_validator_set(shard);
|
auto val_set = last_masterchain_state_->get_next_validator_set(shard);
|
||||||
|
|
||||||
auto validator_id = get_validator(val_set);
|
auto validator_id = get_validator(shard, val_set);
|
||||||
if (!validator_id.is_zero()) {
|
if (!validator_id.is_zero()) {
|
||||||
auto val_group_id = get_validator_set_id(shard, val_set, opts_hash);
|
auto val_group_id = get_validator_set_id(shard, val_set, opts_hash);
|
||||||
auto it = next_validator_groups_.find(val_group_id);
|
auto it = next_validator_groups_.find(val_group_id);
|
||||||
|
@ -1548,7 +1592,7 @@ void ValidatorManagerImpl::update_shards() {
|
||||||
});
|
});
|
||||||
td::actor::send_closure(db_, &Db::update_destroyed_validator_sessions, gc_list_, std::move(P));
|
td::actor::send_closure(db_, &Db::update_destroyed_validator_sessions, gc_list_, std::move(P));
|
||||||
}
|
}
|
||||||
}
|
} // namespace validator
|
||||||
|
|
||||||
void ValidatorManagerImpl::written_destroyed_validator_sessions(std::vector<td::actor::ActorId<ValidatorGroup>> list) {
|
void ValidatorManagerImpl::written_destroyed_validator_sessions(std::vector<td::actor::ActorId<ValidatorGroup>> list) {
|
||||||
for (auto &v : list) {
|
for (auto &v : list) {
|
||||||
|
@ -1609,7 +1653,7 @@ td::actor::ActorOwn<ValidatorGroup> ValidatorManagerImpl::create_validator_group
|
||||||
if (check_gc_list_.count(session_id) == 1) {
|
if (check_gc_list_.count(session_id) == 1) {
|
||||||
return td::actor::ActorOwn<ValidatorGroup>{};
|
return td::actor::ActorOwn<ValidatorGroup>{};
|
||||||
} else {
|
} else {
|
||||||
auto validator_id = get_validator(validator_set);
|
auto validator_id = get_validator(shard, validator_set);
|
||||||
CHECK(!validator_id.is_zero());
|
CHECK(!validator_id.is_zero());
|
||||||
auto G = td::actor::create_actor<ValidatorGroup>("validatorgroup", shard, validator_id, session_id, validator_set,
|
auto G = td::actor::create_actor<ValidatorGroup>("validatorgroup", shard, validator_id, session_id, validator_set,
|
||||||
opts, keyring_, adnl_, rldp_, overlays_, db_root_, actor_id(this),
|
opts, keyring_, adnl_, rldp_, overlays_, db_root_, actor_id(this),
|
||||||
|
@ -1827,10 +1871,26 @@ void ValidatorManagerImpl::advance_gc(BlockHandle handle, td::Ref<MasterchainSta
|
||||||
try_advance_gc_masterchain_block();
|
try_advance_gc_masterchain_block();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerImpl::update_shard_client_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||||
|
auto seqno = handle->id().seqno();
|
||||||
|
shard_client_update(seqno);
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::shard_client_update(BlockSeqno seqno) {
|
void ValidatorManagerImpl::shard_client_update(BlockSeqno seqno) {
|
||||||
if (min_confirmed_masterchain_seqno_ < seqno) {
|
if (min_confirmed_masterchain_seqno_ < seqno) {
|
||||||
min_confirmed_masterchain_seqno_ = seqno;
|
min_confirmed_masterchain_seqno_ = seqno;
|
||||||
}
|
}
|
||||||
|
while (shard_client_waiters_.size() > 0) {
|
||||||
|
auto it = shard_client_waiters_.begin();
|
||||||
|
if (it->first > seqno) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (auto &y : it->second.waiting_) {
|
||||||
|
y.promise.set_value(td::Unit());
|
||||||
|
}
|
||||||
|
shard_client_waiters_.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::state_serializer_update(BlockSeqno seqno) {
|
void ValidatorManagerImpl::state_serializer_update(BlockSeqno seqno) {
|
||||||
|
@ -1870,6 +1930,9 @@ void ValidatorManagerImpl::alarm() {
|
||||||
for (auto &w : wait_state_) {
|
for (auto &w : wait_state_) {
|
||||||
w.second.check_timers();
|
w.second.check_timers();
|
||||||
}
|
}
|
||||||
|
for (auto &w : shard_client_waiters_) {
|
||||||
|
w.second.check_timers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
alarm_timestamp().relax(check_waiters_at_);
|
alarm_timestamp().relax(check_waiters_at_);
|
||||||
if (check_shard_clients_.is_in_past()) {
|
if (check_shard_clients_.is_in_past()) {
|
||||||
|
@ -1904,8 +1967,12 @@ void ValidatorManagerImpl::update_shard_client_state(BlockIdExt masterchain_bloc
|
||||||
td::actor::send_closure(db_, &Db::update_shard_client_state, masterchain_block_id, std::move(promise));
|
td::actor::send_closure(db_, &Db::update_shard_client_state, masterchain_block_id, std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::get_shard_client_state(td::Promise<BlockIdExt> promise) {
|
void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) {
|
||||||
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
|
if (!shard_client_.empty() && !from_db) {
|
||||||
|
td::actor::send_closure(shard_client_, &ShardClient::get_processed_masterchain_block_id, std::move(promise));
|
||||||
|
} else {
|
||||||
|
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::subscribe_to_shard(ShardIdFull shard) {
|
void ValidatorManagerImpl::subscribe_to_shard(ShardIdFull shard) {
|
||||||
|
@ -1928,7 +1995,10 @@ bool ValidatorManagerImpl::is_validator() {
|
||||||
return temp_keys_.size() > 0 || permanent_keys_.size() > 0;
|
return temp_keys_.size() > 0 || permanent_keys_.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PublicKeyHash ValidatorManagerImpl::get_validator(td::Ref<ValidatorSet> val_set) {
|
PublicKeyHash ValidatorManagerImpl::get_validator(ShardIdFull shard, td::Ref<ValidatorSet> val_set) {
|
||||||
|
if (!opts_->need_validate(shard)) {
|
||||||
|
return PublicKeyHash::zero();
|
||||||
|
}
|
||||||
for (auto &key : temp_keys_) {
|
for (auto &key : temp_keys_) {
|
||||||
if (val_set->is_validator(key.bits256_value())) {
|
if (val_set->is_validator(key.bits256_value())) {
|
||||||
return key;
|
return key;
|
||||||
|
@ -2017,6 +2087,28 @@ void ValidatorManagerImpl::prepare_stats(td::Promise<std::vector<std::pair<std::
|
||||||
td::actor::send_closure(db_, &Db::prepare_stats, merger.make_promise("db."));
|
td::actor::send_closure(db_, &Db::prepare_stats, merger.make_promise("db."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerImpl::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {
|
||||||
|
td::actor::send_closure(db_, &Db::truncate, std::move(state), std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerImpl::wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout,
|
||||||
|
td::Promise<td::Unit> promise) {
|
||||||
|
if (seqno <= min_confirmed_masterchain_seqno_) {
|
||||||
|
promise.set_value(td::Unit());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (timeout.is_in_past()) {
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::timeout, "timeout"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (seqno > min_confirmed_masterchain_seqno_ + 100) {
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::notready, "too big masterchain block seqno"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shard_client_waiters_[seqno].waiting_.emplace_back(timeout, 0, std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
|
td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
|
||||||
td::Ref<ValidatorManagerOptions> opts, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
|
td::Ref<ValidatorManagerOptions> opts, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
|
||||||
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
|
||||||
|
|
|
@ -143,6 +143,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
std::vector<Waiter<ResType>> waiting_;
|
std::vector<Waiter<ResType>> waiting_;
|
||||||
td::actor::ActorId<ActorT> actor_;
|
td::actor::ActorId<ActorT> actor_;
|
||||||
|
|
||||||
|
WaitList() = default;
|
||||||
|
|
||||||
std::pair<td::Timestamp, td::uint32> get_timeout() const {
|
std::pair<td::Timestamp, td::uint32> get_timeout() const {
|
||||||
td::Timestamp t = td::Timestamp::now();
|
td::Timestamp t = td::Timestamp::now();
|
||||||
td::uint32 prio = 0;
|
td::uint32 prio = 0;
|
||||||
|
@ -256,6 +258,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
void advance_gc(BlockHandle handle, td::Ref<MasterchainState> state);
|
void advance_gc(BlockHandle handle, td::Ref<MasterchainState> state);
|
||||||
void try_advance_gc_masterchain_block();
|
void try_advance_gc_masterchain_block();
|
||||||
void update_gc_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
void update_gc_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
||||||
|
void update_shard_client_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void install_callback(std::unique_ptr<Callback> new_callback, td::Promise<td::Unit> promise) override {
|
void install_callback(std::unique_ptr<Callback> new_callback, td::Promise<td::Unit> promise) override {
|
||||||
|
@ -414,7 +417,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
void send_block_broadcast(BlockBroadcast broadcast) override;
|
void send_block_broadcast(BlockBroadcast broadcast) override;
|
||||||
|
|
||||||
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
|
||||||
void get_shard_client_state(td::Promise<BlockIdExt> promise) override;
|
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
|
||||||
void subscribe_to_shard(ShardIdFull shard) override;
|
void subscribe_to_shard(ShardIdFull shard) override;
|
||||||
|
|
||||||
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
|
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
|
||||||
|
@ -448,7 +451,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
void read_gc_list(std::vector<ValidatorSessionId> list);
|
void read_gc_list(std::vector<ValidatorSessionId> list);
|
||||||
|
|
||||||
bool is_validator();
|
bool is_validator();
|
||||||
PublicKeyHash get_validator(td::Ref<ValidatorSet> val_set);
|
PublicKeyHash get_validator(ShardIdFull shard, td::Ref<ValidatorSet> val_set);
|
||||||
|
|
||||||
ValidatorManagerImpl(td::Ref<ValidatorManagerOptions> opts, std::string db_root,
|
ValidatorManagerImpl(td::Ref<ValidatorManagerOptions> opts, std::string db_root,
|
||||||
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
|
||||||
|
@ -502,6 +505,10 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
|
|
||||||
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override;
|
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override;
|
||||||
|
|
||||||
|
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) override;
|
||||||
|
|
||||||
|
void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
td::Timestamp resend_shard_blocks_at_;
|
td::Timestamp resend_shard_blocks_at_;
|
||||||
td::Timestamp check_waiters_at_;
|
td::Timestamp check_waiters_at_;
|
||||||
|
@ -558,6 +565,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
double block_ttl() const {
|
double block_ttl() const {
|
||||||
return opts_->block_ttl();
|
return opts_->block_ttl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<BlockSeqno, WaitList<td::actor::Actor, td::Unit>> shard_client_waiters_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
|
@ -36,7 +36,7 @@ void ShardClient::start_up() {
|
||||||
R.ensure();
|
R.ensure();
|
||||||
td::actor::send_closure(SelfId, &ShardClient::got_state_from_db, R.move_as_ok());
|
td::actor::send_closure(SelfId, &ShardClient::got_state_from_db, R.move_as_ok());
|
||||||
});
|
});
|
||||||
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, std::move(P));
|
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, true, std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShardClient::got_state_from_db(BlockIdExt state) {
|
void ShardClient::got_state_from_db(BlockIdExt state) {
|
||||||
|
@ -94,6 +94,8 @@ void ShardClient::saved_to_db() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(masterchain_block_handle_);
|
CHECK(masterchain_block_handle_);
|
||||||
|
td::actor::send_closure(manager_, &ValidatorManager::update_shard_client_block_handle, masterchain_block_handle_,
|
||||||
|
[](td::Unit) {});
|
||||||
if (masterchain_block_handle_->inited_next_left()) {
|
if (masterchain_block_handle_->inited_next_left()) {
|
||||||
new_masterchain_block_id(masterchain_block_handle_->one_next(true));
|
new_masterchain_block_id(masterchain_block_handle_->one_next(true));
|
||||||
} else {
|
} else {
|
||||||
|
@ -198,6 +200,14 @@ void ShardClient::get_processed_masterchain_block(td::Promise<BlockSeqno> promis
|
||||||
promise.set_result(seqno);
|
promise.set_result(seqno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShardClient::get_processed_masterchain_block_id(td::Promise<BlockIdExt> promise) {
|
||||||
|
if (masterchain_block_handle_) {
|
||||||
|
promise.set_result(masterchain_block_handle_->id());
|
||||||
|
} else {
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::notready, "shard client not started"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ShardClient::build_shard_overlays() {
|
void ShardClient::build_shard_overlays() {
|
||||||
auto v = masterchain_state_->get_shards();
|
auto v = masterchain_state_->get_shards();
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ class ShardClient : public td::actor::Actor {
|
||||||
void new_masterchain_block_notification(BlockHandle handle, td::Ref<MasterchainState> state);
|
void new_masterchain_block_notification(BlockHandle handle, td::Ref<MasterchainState> state);
|
||||||
|
|
||||||
void get_processed_masterchain_block(td::Promise<BlockSeqno> promise);
|
void get_processed_masterchain_block(td::Promise<BlockSeqno> promise);
|
||||||
|
void get_processed_masterchain_block_id(td::Promise<BlockIdExt> promise);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace ton {
|
||||||
namespace validator {
|
namespace validator {
|
||||||
|
|
||||||
td::Ref<ValidatorManagerOptions> ValidatorManagerOptions::create(
|
td::Ref<ValidatorManagerOptions> ValidatorManagerOptions::create(
|
||||||
BlockIdExt zero_block_id, BlockIdExt init_block_id, std::function<bool(ShardIdFull)> check_shard,
|
BlockIdExt zero_block_id, BlockIdExt init_block_id, std::function<bool(ShardIdFull, ShardCheckMode)> check_shard,
|
||||||
bool allow_blockchain_init, td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
|
bool allow_blockchain_init, td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
|
||||||
td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration archive_ttl, td::ClocksBase::Duration key_proof_ttl,
|
td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration archive_ttl, td::ClocksBase::Duration key_proof_ttl,
|
||||||
bool initial_sync_disabled) {
|
bool initial_sync_disabled) {
|
||||||
|
|
|
@ -33,7 +33,10 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
||||||
return init_block_id_;
|
return init_block_id_;
|
||||||
}
|
}
|
||||||
bool need_monitor(ShardIdFull shard) const override {
|
bool need_monitor(ShardIdFull shard) const override {
|
||||||
return check_shard_(shard);
|
return check_shard_(shard, ShardCheckMode::m_monitor);
|
||||||
|
}
|
||||||
|
bool need_validate(ShardIdFull shard) const override {
|
||||||
|
return check_shard_(shard, ShardCheckMode::m_validate);
|
||||||
}
|
}
|
||||||
bool allow_blockchain_init() const override {
|
bool allow_blockchain_init() const override {
|
||||||
return allow_blockchain_init_;
|
return allow_blockchain_init_;
|
||||||
|
@ -82,6 +85,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
||||||
td::uint32 get_last_fork_masterchain_seqno() const override {
|
td::uint32 get_last_fork_masterchain_seqno() const override {
|
||||||
return hardforks_.size() ? hardforks_.rbegin()->seqno() : 0;
|
return hardforks_.size() ? hardforks_.rbegin()->seqno() : 0;
|
||||||
}
|
}
|
||||||
|
std::vector<BlockIdExt> get_hardforks() const override {
|
||||||
|
return hardforks_;
|
||||||
|
}
|
||||||
td::uint32 get_filedb_depth() const override {
|
td::uint32 get_filedb_depth() const override {
|
||||||
return db_depth_;
|
return db_depth_;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +98,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
||||||
void set_init_block_id(BlockIdExt block_id) override {
|
void set_init_block_id(BlockIdExt block_id) override {
|
||||||
init_block_id_ = block_id;
|
init_block_id_ = block_id;
|
||||||
}
|
}
|
||||||
void set_shard_check_function(std::function<bool(ShardIdFull)> check_shard) override {
|
void set_shard_check_function(std::function<bool(ShardIdFull, ShardCheckMode)> check_shard) override {
|
||||||
check_shard_ = std::move(check_shard);
|
check_shard_ = std::move(check_shard);
|
||||||
}
|
}
|
||||||
void set_allow_blockchain_init(bool value) override {
|
void set_allow_blockchain_init(bool value) override {
|
||||||
|
@ -129,7 +135,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidatorManagerOptionsImpl(BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
ValidatorManagerOptionsImpl(BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
||||||
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
|
std::function<bool(ShardIdFull, ShardCheckMode)> check_shard, bool allow_blockchain_init,
|
||||||
td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
|
td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
|
||||||
td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration archive_ttl,
|
td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration archive_ttl,
|
||||||
td::ClocksBase::Duration key_proof_ttl, bool initial_sync_disabled)
|
td::ClocksBase::Duration key_proof_ttl, bool initial_sync_disabled)
|
||||||
|
@ -148,7 +154,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
|
||||||
private:
|
private:
|
||||||
BlockIdExt zero_block_id_;
|
BlockIdExt zero_block_id_;
|
||||||
BlockIdExt init_block_id_;
|
BlockIdExt init_block_id_;
|
||||||
std::function<bool(ShardIdFull)> check_shard_;
|
std::function<bool(ShardIdFull, ShardCheckMode)> check_shard_;
|
||||||
bool allow_blockchain_init_;
|
bool allow_blockchain_init_;
|
||||||
td::ClocksBase::Duration sync_blocks_before_;
|
td::ClocksBase::Duration sync_blocks_before_;
|
||||||
td::ClocksBase::Duration block_ttl_;
|
td::ClocksBase::Duration block_ttl_;
|
||||||
|
|
|
@ -46,9 +46,12 @@ class DownloadToken {
|
||||||
|
|
||||||
struct ValidatorManagerOptions : public td::CntObject {
|
struct ValidatorManagerOptions : public td::CntObject {
|
||||||
public:
|
public:
|
||||||
|
enum class ShardCheckMode { m_monitor, m_validate };
|
||||||
|
|
||||||
virtual BlockIdExt zero_block_id() const = 0;
|
virtual BlockIdExt zero_block_id() const = 0;
|
||||||
virtual BlockIdExt init_block_id() const = 0;
|
virtual BlockIdExt init_block_id() const = 0;
|
||||||
virtual bool need_monitor(ShardIdFull shard) const = 0;
|
virtual bool need_monitor(ShardIdFull shard) const = 0;
|
||||||
|
virtual bool need_validate(ShardIdFull shard) const = 0;
|
||||||
virtual bool allow_blockchain_init() const = 0;
|
virtual bool allow_blockchain_init() const = 0;
|
||||||
virtual td::ClocksBase::Duration sync_blocks_before() const = 0;
|
virtual td::ClocksBase::Duration sync_blocks_before() const = 0;
|
||||||
virtual td::ClocksBase::Duration block_ttl() const = 0;
|
virtual td::ClocksBase::Duration block_ttl() const = 0;
|
||||||
|
@ -60,6 +63,7 @@ struct ValidatorManagerOptions : public td::CntObject {
|
||||||
virtual td::uint32 get_vertical_seqno(BlockSeqno seqno) const = 0;
|
virtual td::uint32 get_vertical_seqno(BlockSeqno seqno) const = 0;
|
||||||
virtual td::uint32 get_maximal_vertical_seqno() const = 0;
|
virtual td::uint32 get_maximal_vertical_seqno() const = 0;
|
||||||
virtual td::uint32 get_last_fork_masterchain_seqno() const = 0;
|
virtual td::uint32 get_last_fork_masterchain_seqno() const = 0;
|
||||||
|
virtual std::vector<BlockIdExt> get_hardforks() const = 0;
|
||||||
virtual td::uint32 get_filedb_depth() const = 0;
|
virtual td::uint32 get_filedb_depth() const = 0;
|
||||||
virtual td::uint32 key_block_utime_step() const {
|
virtual td::uint32 key_block_utime_step() const {
|
||||||
return 86400;
|
return 86400;
|
||||||
|
@ -67,7 +71,7 @@ struct ValidatorManagerOptions : public td::CntObject {
|
||||||
|
|
||||||
virtual void set_zero_block_id(BlockIdExt block_id) = 0;
|
virtual void set_zero_block_id(BlockIdExt block_id) = 0;
|
||||||
virtual void set_init_block_id(BlockIdExt block_id) = 0;
|
virtual void set_init_block_id(BlockIdExt block_id) = 0;
|
||||||
virtual void set_shard_check_function(std::function<bool(ShardIdFull)> check_shard) = 0;
|
virtual void set_shard_check_function(std::function<bool(ShardIdFull, ShardCheckMode)> check_shard) = 0;
|
||||||
virtual void set_allow_blockchain_init(bool value) = 0;
|
virtual void set_allow_blockchain_init(bool value) = 0;
|
||||||
virtual void set_sync_blocks_before(td::ClocksBase::Duration value) = 0;
|
virtual void set_sync_blocks_before(td::ClocksBase::Duration value) = 0;
|
||||||
virtual void set_block_ttl(td::ClocksBase::Duration value) = 0;
|
virtual void set_block_ttl(td::ClocksBase::Duration value) = 0;
|
||||||
|
@ -80,7 +84,7 @@ struct ValidatorManagerOptions : public td::CntObject {
|
||||||
|
|
||||||
static td::Ref<ValidatorManagerOptions> create(
|
static td::Ref<ValidatorManagerOptions> create(
|
||||||
BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
BlockIdExt zero_block_id, BlockIdExt init_block_id,
|
||||||
std::function<bool(ShardIdFull)> check_shard = [](ShardIdFull) { return true; },
|
std::function<bool(ShardIdFull, ShardCheckMode)> check_shard = [](ShardIdFull, ShardCheckMode) { return true; },
|
||||||
bool allow_blockchain_init = false, td::ClocksBase::Duration sync_blocks_before = 300,
|
bool allow_blockchain_init = false, td::ClocksBase::Duration sync_blocks_before = 300,
|
||||||
td::ClocksBase::Duration block_ttl = 86400 * 7, td::ClocksBase::Duration state_ttl = 3600,
|
td::ClocksBase::Duration block_ttl = 86400 * 7, td::ClocksBase::Duration state_ttl = 3600,
|
||||||
td::ClocksBase::Duration archive_ttl = 86400 * 365, td::ClocksBase::Duration key_proof_ttl = 86400 * 3650,
|
td::ClocksBase::Duration archive_ttl = 86400 * 365, td::ClocksBase::Duration key_proof_ttl = 86400 * 3650,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue