Repository: paritytech/substrate
File: frame/im-online/src/lib.rs (Rust)

Code before:
	#[pallet::event]
	#[pallet::generate_deposit(pub(super) fn deposit_event)]
	#[pallet::metadata(T::AuthorityId = "AuthorityId", Vec<IdentificationTuple<T>> = "Vec<IdentificationTuple>")]
	pub enum Event<T: Config> {
		/// A new heartbeat was received from `AuthorityId` \[authority_id\]
		HeartbeatReceived(T::AuthorityId),
		/// At the end of the session, no offence was committed.
		AllGood,
		/// At the end of the session, at least one validator was found to be \[offline\].
		SomeOffline(Vec<IdentificationTuple<T>>),
	}

	#[pallet::error]
	pub enum Error<T> {
		/// Non existent public key.
		InvalidKey,
		/// Duplicated heartbeat.
		DuplicatedHeartbeat,
	}

	/// The block number after which it's ok to send heartbeats in the current
	/// session.
	///
	/// At the beginning of each session we set this to a value that should fall
	/// roughly in the middle of the session duration. The idea is to first wait for
	/// the validators to produce a block in the current session, so that the
	/// heartbeat later on will not be necessary.
	///
	/// This value will only be used as a fallback if we fail to get a proper session
	/// progress estimate from `NextSessionRotation`, as those estimates should be
	/// more accurate then the value we calculate for `HeartbeatAfter`.
	#[pallet::storage]
	#[pallet::getter(fn heartbeat_after)]
	pub(crate) type HeartbeatAfter<T: Config> = StorageValue<_, T::BlockNumber, ValueQuery>;

	/// The current set of keys that may issue a heartbeat.
	#[pallet::storage]
	#[pallet::getter(fn keys)]
	pub(crate) type Keys<T: Config> =
		StorageValue<_, WeakBoundedVec<T::AuthorityId, T::MaxKeys>, ValueQuery>;

	/// For each session index, we keep a mapping of `AuthIndex` to
	/// `offchain::OpaqueNetworkState`.
	#[pallet::storage]
	#[pallet::getter(fn received_heartbeats)]
	pub(crate) type ReceivedHeartbeats<T: Config> = StorageDoubleMap<
		_,
		Twox64Concat,
		SessionIndex,
		Twox64Concat,
		AuthIndex,

Review comment (suggestion):
This doesn't describe its current usage. Currently this limit the number of bytes the encoding of the network state of the heartbeat.
Not the number of Peer.

Either we update the doc to say precisely what is this limit. But then this limit is a bit difficult to configure, or we update our usage of this limit.

We can do that by create a structure `BoundedHeartBeat<BlockNumber, Limit>` with the field `BoundedOpaqueNetworkState<Limit>` which would be generic over the limit. Maybe we can create a wrapper type to encode BoundedHeartBeat with the compact u32 in front of type. like a new struct `WrapperOpaque<Foo>(Foo)`.

So then we implement MaxEncodedLen on WrapperOpaque, BoundedHeartBeat and BoundedOpaqueNetworkState. And put into the storage the type `WrapperOpaque<BoundedHeartBeat<BlockNumber, MaxPeerInHearbeats>>`

(the type WrapperOpaque might be handy we can put it in frame_support probably)

Code after:
			InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
			ValidTransaction,
		},
	};

	#[pallet::pallet]
	#[pallet::generate_store(pub(super) trait Store)]
	#[pallet::generate_storage_info]
	pub struct Pallet<T>(_);

	#[pallet::config]
	pub trait Config: SendTransactionTypes<Call<Self>> + frame_system::Config {
		/// The identifier type for an authority.
		type AuthorityId: Member
			+ Parameter
			+ RuntimeAppPublic
			+ Default
			+ Ord
			+ MaybeSerializeDeserialize
			+ MaxEncodedLen;

		/// The maximum number of keys that can be added.
		type MaxKeys: Get<u32>;

		/// The maximum number of peers to be stored in `ReceivedHeartbeats`
		type MaxPeerInHeartbeats: Get<u32>;

		/// The maximum size of the encoding of `PeerId` and `MultiAddr` that are coming
		/// from the hearbeat
		type MaxPeerDataEncodingSize: Get<u32>;

		/// The overarching event type.
		type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;

		/// A type for retrieving the validators supposed to be online in a session.
		type ValidatorSet: ValidatorSetWithIdentification<Self::AccountId>;

		/// A trait that allows us to estimate the current session progress and also the
		/// average session length.
		///
		/// This parameter is used to determine the longevity of `heartbeat` transaction and a
		/// rough time when we should start considering sending heartbeats, since the workers
		/// avoids sending them at the very beginning of the session, assuming there is a
		/// chance the authority will produce a block and they won't be necessary.
		type NextSessionRotation: EstimateNextSessionRotation<Self::BlockNumber>;

		/// A type that gives us the ability to submit unresponsiveness offence reports.
		type ReportUnresponsiveness: ReportOffence<
			Self::AccountId,
			IdentificationTuple<Self>,
			UnresponsivenessOffence<IdentificationTuple<Self>>,