public override void Init()
        {
            if (Logger.IsTrace)
            {
                Logger.Trace($"{ProtocolCode} v{ProtocolVersion} subprotocol initializing with {Session.Node:c}");
            }
            if (SyncServer.Head == null)
            {
                throw new InvalidOperationException($"Cannot initialize {ProtocolCode} v{ProtocolVersion} protocol without the head block set");
            }

            BlockHeader   head          = SyncServer.Head;
            StatusMessage statusMessage = new StatusMessage
            {
                ProtocolVersion = ProtocolVersion,
                ChainId         = (UInt256)SyncServer.ChainId,
                TotalDifficulty = head.TotalDifficulty ?? head.Difficulty,
                BestHash        = head.Hash,
                HeadBlockNo     = head.Number,
                GenesisHash     = SyncServer.Genesis.Hash,

                // TODO - implement config option for these
                ServeHeaders    = true,
                ServeChainSince = 0x00,
                //if (config.recentchain != null)
                //    ServeRecentChain = Config.recentchain
                ServeStateSince = 0x00,
                //if (Config.serverecentstate != null)
                //    ServeRecentState = Config.RecentState
                TxRelay = true,
                // TODO - should allow setting to infinite
                BufferLimit         = int.MaxValue,
                MaximumRechargeRate = int.MaxValue
            };

            Send(statusMessage);

            if (NetworkDiagTracer.IsEnabled)
            {
                NetworkDiagTracer.ReportOutgoingMessage(Session.Node.Address, Name, statusMessage.ToString());
            }
            Metrics.LesStatusesSent++;

            CheckProtocolInitTimeout().ContinueWith(x =>
            {
                if (x.IsFaulted && Logger.IsError)
                {
                    Logger.Error("Error during lesProtocol handler timeout logic", x.Exception);
                }
            });
        }
        public override void HandleMessage(ZeroPacket message)
        {
            if (message.PacketType != LesMessageCode.Status && !_statusReceived)
            {
                throw new SubprotocolException($"No {nameof(StatusMessage)} received prior to communication with {Session.Node:c}.");
            }

            int size = message.Content.ReadableBytes;

            switch (message.PacketType)
            {
            case LesMessageCode.Status:
                StatusMessage statusMessage = Deserialize <StatusMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Host, Name, statusMessage.ToString());
                }
                Handle(statusMessage);
                break;
            }
        }
        public override void HandleMessage(ZeroPacket message)
        {
            if (message.PacketType != LesMessageCode.Status && !_statusReceived)
            {
                throw new SubprotocolException($"No {nameof(StatusMessage)} received prior to communication with {Session.Node:c}.");
            }

            int size = message.Content.ReadableBytes;

            switch (message.PacketType)
            {
            case LesMessageCode.Status:
                StatusMessage statusMessage = Deserialize <StatusMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, statusMessage.ToString());
                }
                Handle(statusMessage);
                break;

            case LesMessageCode.GetBlockHeaders:
                GetBlockHeadersMessage getBlockHeadersMessage = Deserialize <GetBlockHeadersMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, getBlockHeadersMessage.ToString());
                }
                Handle(getBlockHeadersMessage);
                break;

            case LesMessageCode.GetBlockBodies:
                GetBlockBodiesMessage getBlockBodiesMessage = Deserialize <GetBlockBodiesMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, getBlockBodiesMessage.ToString());
                }
                Handle(getBlockBodiesMessage);
                break;

            case LesMessageCode.GetReceipts:
                GetReceiptsMessage getReceiptsMessage = Deserialize <GetReceiptsMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, getReceiptsMessage.ToString());
                }
                Handle(getReceiptsMessage);
                break;

            case LesMessageCode.GetContractCodes:
                GetContractCodesMessage getContractCodesMessage = Deserialize <GetContractCodesMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, getContractCodesMessage.ToString());
                }
                Handle(getContractCodesMessage);
                break;

            case LesMessageCode.GetHelperTrieProofs:
                GetHelperTrieProofsMessage getHelperTrieProofsMessage = Deserialize <GetHelperTrieProofsMessage>(message.Content);
                if (NetworkDiagTracer.IsEnabled)
                {
                    NetworkDiagTracer.ReportIncomingMessage(Session.Node.Address, Name, getHelperTrieProofsMessage.ToString());
                }
                Handle(getHelperTrieProofsMessage);
                break;
            }
        }