mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			314 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			314 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|     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 "auto/tl/ton_api.h"
 | |
| #include "overlay/overlay.h"
 | |
| #include "td/utils/List.h"
 | |
| #include "fec/fec.h"
 | |
| #include "common/checksum.h"
 | |
| 
 | |
| #include <set>
 | |
| 
 | |
| namespace ton {
 | |
| 
 | |
| namespace overlay {
 | |
| 
 | |
| class OverlayImpl;
 | |
| 
 | |
| class BroadcastFec : public td::ListNode {
 | |
|  public:
 | |
|   bool finalized() const {
 | |
|     return ready_;
 | |
|   }
 | |
| 
 | |
|   bool has_encoder() const {
 | |
|     return encoder_ != nullptr;
 | |
|   }
 | |
| 
 | |
|   auto get_hash() const {
 | |
|     return hash_;
 | |
|   }
 | |
| 
 | |
|   auto get_data_hash() const {
 | |
|     return data_hash_;
 | |
|   }
 | |
| 
 | |
|   td::uint32 get_date() const {
 | |
|     return date_;
 | |
|   }
 | |
| 
 | |
|   auto get_flags() const {
 | |
|     return flags_;
 | |
|   }
 | |
| 
 | |
|   const auto &get_fec_type() const {
 | |
|     return fec_type_;
 | |
|   }
 | |
| 
 | |
|   auto get_source() const {
 | |
|     return src_;
 | |
|   }
 | |
| 
 | |
|   auto get_size() const {
 | |
|     return fec_type_.size();
 | |
|   }
 | |
| 
 | |
|   td::Status is_eligible_sender(PublicKey src) {
 | |
|     if (flags_ & Overlays::BroadcastFlagAnySender()) {
 | |
|       return td::Status::OK();
 | |
|     } else {
 | |
|       if (src == src_) {
 | |
|         return td::Status::OK();
 | |
|       } else {
 | |
|         return td::Status::Error(ErrorCode::protoviolation, "bad source");
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   td::Status add_part(td::uint32 seqno, td::BufferSlice data) {
 | |
|     CHECK(decoder_);
 | |
|     td::fec::Symbol s;
 | |
|     s.id = seqno;
 | |
|     s.data = std::move(data);
 | |
| 
 | |
|     decoder_->add_symbol(std::move(s));
 | |
| 
 | |
|     return td::Status::OK();
 | |
|   }
 | |
| 
 | |
|   td::Result<td::BufferSlice> finish() {
 | |
|     CHECK(decoder_);
 | |
|     if (!decoder_->may_try_decode()) {
 | |
|       return td::Status::Error(ErrorCode::notready, "need more parts");
 | |
|     }
 | |
|     TRY_RESULT(D, decoder_->try_decode(true));
 | |
|     if (sha256_bits256(D.data.as_slice()) != data_hash_) {
 | |
|       return td::Status::Error(ErrorCode::protoviolation, "bad hash");
 | |
|     }
 | |
|     encoder_ = std::move(D.encoder);
 | |
|     CHECK(encoder_ != nullptr);
 | |
|     ready_ = true;
 | |
|     decoder_ = nullptr;
 | |
|     return std::move(D.data);
 | |
|   }
 | |
| 
 | |
|   td::BufferSlice get_part(td::uint32 seqno) {
 | |
|     CHECK(ready_);
 | |
|     CHECK(encoder_ != nullptr);
 | |
|     auto R = encoder_->gen_symbol(seqno);
 | |
|     CHECK(R.id == seqno);
 | |
|     return std::move(R.data);
 | |
|   }
 | |
| 
 | |
|   td::Status init_fec_type() {
 | |
|     TRY_RESULT(D, fec_type_.create_decoder());
 | |
|     decoder_ = std::move(D);
 | |
|     return td::Status::OK();
 | |
|   }
 | |
| 
 | |
|   td::Status run_checks();
 | |
| 
 | |
|   BroadcastFec(Overlay::BroadcastHash hash, PublicKey src, Overlay::BroadcastDataHash data_hash, td::uint32 flags,
 | |
|                td::uint32 date, fec::FecType fec_type)
 | |
|       : hash_(hash)
 | |
|       , data_hash_(data_hash)
 | |
|       , flags_(flags)
 | |
|       , date_(date)
 | |
|       , src_(std::move(src))
 | |
|       , fec_type_(std::move(fec_type)) {
 | |
|   }
 | |
| 
 | |
|   static td::Result<std::unique_ptr<BroadcastFec>> create(Overlay::BroadcastHash hash, PublicKey src,
 | |
|                                                           Overlay::BroadcastDataHash data_hash, td::uint32 flags,
 | |
|                                                           td::uint32 date, fec::FecType fec_type);
 | |
| 
 | |
|   bool neighbour_received(adnl::AdnlNodeIdShort id) const {
 | |
|     return received_neighbours_.find(id) != received_neighbours_.end();
 | |
|   }
 | |
| 
 | |
|   void add_received(adnl::AdnlNodeIdShort id) {
 | |
|     received_neighbours_.insert(id);
 | |
|   }
 | |
| 
 | |
|   bool neighbour_completed(adnl::AdnlNodeIdShort id) const {
 | |
|     return completed_neighbours_.find(id) != completed_neighbours_.end();
 | |
|   }
 | |
| 
 | |
|   void add_completed(adnl::AdnlNodeIdShort id) {
 | |
|     completed_neighbours_.insert(id);
 | |
|   }
 | |
| 
 | |
|   static BroadcastFec *from_list_node(ListNode *node) {
 | |
|     return static_cast<BroadcastFec *>(node);
 | |
|   }
 | |
| 
 | |
|   bool received_part(td::uint32 seqno) const {
 | |
|     if (seqno + 64 < next_seqno_) {
 | |
|       return true;
 | |
|     }
 | |
|     if (seqno >= next_seqno_) {
 | |
|       return false;
 | |
|     }
 | |
|     return received_parts_ & (1ull << (next_seqno_ - seqno - 1));
 | |
|   }
 | |
| 
 | |
|   void add_received_part(td::uint32 seqno) {
 | |
|     CHECK(!received_part(seqno));
 | |
|     if (seqno < next_seqno_) {
 | |
|       received_parts_ |= (1ull << (next_seqno_ - seqno - 1));
 | |
|     } else {
 | |
|       auto old = next_seqno_;
 | |
|       next_seqno_ = seqno + 1;
 | |
|       if (next_seqno_ - old >= 64) {
 | |
|         received_parts_ = 1;
 | |
|       } else {
 | |
|         received_parts_ = received_parts_ << (next_seqno_ - old);
 | |
|         received_parts_ |= 1;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   bool ready_ = false;
 | |
| 
 | |
|   Overlay::BroadcastHash hash_;
 | |
|   Overlay::BroadcastDataHash data_hash_;
 | |
| 
 | |
|   td::uint32 flags_;
 | |
|   td::uint32 date_;
 | |
| 
 | |
|   PublicKey src_;
 | |
|   fec::FecType fec_type_;
 | |
| 
 | |
|   std::unique_ptr<td::fec::Decoder> decoder_;
 | |
|   std::unique_ptr<td::fec::Encoder> encoder_;
 | |
| 
 | |
|   std::set<adnl::AdnlNodeIdShort> received_neighbours_;
 | |
|   std::set<adnl::AdnlNodeIdShort> completed_neighbours_;
 | |
| 
 | |
|   td::uint32 next_seqno_ = 0;
 | |
|   td::uint64 received_parts_ = 0;
 | |
| };
 | |
| 
 | |
| class OverlayFecBroadcastPart : public td::ListNode {
 | |
|  private:
 | |
|   Overlay::BroadcastHash broadcast_hash_;
 | |
|   Overlay::BroadcastPartHash part_hash_;
 | |
| 
 | |
|   PublicKey source_;
 | |
|   std::shared_ptr<Certificate> cert_;
 | |
|   Overlay::BroadcastDataHash broadcast_data_hash_;
 | |
|   td::uint32 broadcast_size_;
 | |
|   td::uint32 flags_;
 | |
|   Overlay::BroadcastDataHash part_data_hash_;
 | |
|   td::BufferSlice data_;
 | |
|   td::uint32 seqno_;
 | |
|   fec::FecType fec_type_;
 | |
|   td::uint32 date_;
 | |
|   td::BufferSlice signature_;
 | |
| 
 | |
|   bool is_short_;
 | |
| 
 | |
|   BroadcastFec *bcast_;
 | |
|   OverlayImpl *overlay_;
 | |
| 
 | |
|   td::Status check_time();
 | |
|   td::Status check_duplicate();
 | |
|   td::Status check_source();
 | |
|   td::Status check_signature();
 | |
| 
 | |
|   td::Status run_checks();
 | |
|   td::Status apply();
 | |
|   td::Status distribute();
 | |
| 
 | |
|  public:
 | |
|   OverlayFecBroadcastPart(Overlay::BroadcastHash broadcast_hash, Overlay::BroadcastPartHash part_hash, PublicKey source,
 | |
|                           std::shared_ptr<Certificate> cert, Overlay::BroadcastDataHash data_hash, td::uint32 data_size,
 | |
|                           td::uint32 flags, Overlay::BroadcastDataHash part_data_hash, td::BufferSlice data,
 | |
|                           td::uint32 seqno, fec::FecType fec_type, td::uint32 date, td::BufferSlice signature,
 | |
|                           bool is_short, BroadcastFec *bcast, OverlayImpl *overlay)
 | |
|       : broadcast_hash_(broadcast_hash)
 | |
|       , part_hash_(part_hash)
 | |
|       , source_(std::move(source))
 | |
|       , cert_(std::move(cert))
 | |
|       , broadcast_data_hash_(data_hash)
 | |
|       , broadcast_size_(data_size)
 | |
|       , flags_(flags)
 | |
|       , part_data_hash_(part_data_hash)
 | |
|       , data_(std::move(data))
 | |
|       , seqno_(seqno)
 | |
|       , fec_type_(std::move(fec_type))
 | |
|       , date_(date)
 | |
|       , signature_(std::move(signature))
 | |
|       , is_short_(is_short)
 | |
|       , bcast_(bcast)
 | |
|       , overlay_(overlay) {
 | |
|   }
 | |
| 
 | |
|   td::uint32 data_size() const {
 | |
|     return static_cast<td::uint32>(data_.size());
 | |
|   }
 | |
| 
 | |
|   Overlay::BroadcastPartHash get_hash() const {
 | |
|     return part_hash_;
 | |
|   }
 | |
| 
 | |
|   void update_source(PublicKey source) {
 | |
|     source_ = source;
 | |
|   }
 | |
|   void update_signature(td::BufferSlice signature) {
 | |
|     signature_ = std::move(signature);
 | |
|   }
 | |
|   void update_overlay(OverlayImpl *overlay);
 | |
| 
 | |
|   tl_object_ptr<ton_api::overlay_broadcastFec> export_tl();
 | |
|   tl_object_ptr<ton_api::overlay_broadcastFecShort> export_tl_short();
 | |
|   td::BufferSlice export_serialized();
 | |
|   td::BufferSlice export_serialized_short();
 | |
|   td::BufferSlice to_sign();
 | |
| 
 | |
|   td::Status run() {
 | |
|     TRY_STATUS(run_checks());
 | |
|     TRY_STATUS(apply());
 | |
|     TRY_STATUS(distribute());
 | |
|     return td::Status::OK();
 | |
|   }
 | |
| 
 | |
|   static td::Status create(OverlayImpl *overlay, tl_object_ptr<ton_api::overlay_broadcastFec> broadcast);
 | |
|   static td::Status create(OverlayImpl *overlay, tl_object_ptr<ton_api::overlay_broadcastFecShort> broadcast);
 | |
|   static td::Status create_new(OverlayImpl *overlay, td::actor::ActorId<OverlayImpl> overlay_actor_id,
 | |
|                                PublicKeyHash local_id, Overlay::BroadcastDataHash data_hash, td::uint32 size,
 | |
|                                td::uint32 flags, td::BufferSlice part, td::uint32 seqno, fec::FecType fec_type,
 | |
|                                td::uint32 date);
 | |
| 
 | |
|   static Overlay::BroadcastHash compute_broadcast_id(PublicKey source, const fec::FecType &fec_type,
 | |
|                                                      Overlay::BroadcastDataHash data_hash, td::uint32 size,
 | |
|                                                      td::uint32 flags);
 | |
|   static Overlay::BroadcastHash compute_broadcast_id(PublicKeyHash source, const fec::FecType &fec_type,
 | |
|                                                      Overlay::BroadcastDataHash data_hash, td::uint32 size,
 | |
|                                                      td::uint32 flags);
 | |
|   static Overlay::BroadcastPartHash compute_broadcast_part_id(Overlay::BroadcastHash broadcast_hash,
 | |
|                                                               Overlay::BroadcastDataHash data_hash, td::uint32 seqno);
 | |
| };
 | |
| 
 | |
| }  // namespace overlay
 | |
| 
 | |
| }  // namespace ton
 | |
| 
 |