public void ReadWrite(BitcoinStream stream) { bool verifyChechksum = false; if (stream.Serializing || (!stream.Serializing && !_SkipMagic)) { stream.ReadWrite(ref magic); } stream.ReadWrite(ref command); stream.ReadWrite(ref length); if (stream.ProtocolVersion >= ProtocolVersion.MEMPOOL_GD_VERSION) { stream.ReadWrite(ref checksum); verifyChechksum = true; } if (stream.Serializing) { stream.ReadWrite(ref payload); } else { NodeServerTrace.Trace.TraceEvent(TraceEventType.Verbose, 0, "Message type readen : " + Command); if (length > 0x02000000) //MAX_SIZE 0x02000000 Serialize.h { throw new FormatException("Message payload too big ( > 0x02000000 bytes)"); } payload = new byte[length]; stream.ReadWrite(ref payload); if (verifyChechksum) { if (!VerifyChecksum()) { NodeServerTrace.Trace.TraceEvent(TraceEventType.Verbose, 0, "Invalid message checksum bytes : " + Encoders.Hex.EncodeData(this.ToBytes())); throw new FormatException("Message checksum invalid"); } } BitcoinStream payloadStream = new BitcoinStream(payload); payloadStream.CopyParameters(stream); var payloadType = PayloadAttribute.GetCommandType(Command); if (payloadType == typeof(UnknowPayload)) { NodeServerTrace.Trace.TraceEvent(TraceEventType.Warning, 0, "Unknown command received : " + Command); } payloadStream.ReadWrite(payloadType, ref _PayloadObject); NodeServerTrace.Verbose("Payload : " + _PayloadObject); } }
public void ReadWrite(BitcoinStream stream) { if (Payload == null && stream.Serializing) { throw new InvalidOperationException("Payload not affected"); } if (stream.Serializing || (!stream.Serializing && !_SkipMagic)) { stream.ReadWrite(ref magic); } stream.ReadWrite(ref command); int length = 0; uint checksum = 0; bool hasChecksum = false; byte[] payloadBytes = stream.Serializing ? GetPayloadBytes(stream.ProtocolVersion, out length) : null; length = payloadBytes == null ? 0 : length; stream.ReadWrite(ref length); if (stream.ProtocolVersion >= ProtocolVersion.MEMPOOL_GD_VERSION) { if (stream.Serializing) { checksum = Hashes.Hash256(payloadBytes, 0, length).GetLow32(); } stream.ReadWrite(ref checksum); hasChecksum = true; } if (stream.Serializing) { stream.ReadWrite(ref payloadBytes, 0, length); } else { if (length > 0x02000000) //MAX_SIZE 0x02000000 Serialize.h { throw new FormatException("Message payload too big ( > 0x02000000 bytes)"); } payloadBytes = _Buffer == null || _Buffer.Length < length ? new byte[length] : _Buffer; stream.ReadWrite(ref payloadBytes, 0, length); if (hasChecksum) { if (!VerifyChecksum(checksum, payloadBytes, length)) { if (NodeServerTrace.Trace.Switch.ShouldTrace(TraceEventType.Verbose)) { NodeServerTrace.Trace.TraceEvent(TraceEventType.Verbose, 0, "Invalid message checksum bytes"); } throw new FormatException("Message checksum invalid"); } } BitcoinStream payloadStream = new BitcoinStream(payloadBytes); payloadStream.CopyParameters(stream); var payloadType = PayloadAttribute.GetCommandType(Command); var unknown = payloadType == typeof(UnknowPayload); if (unknown) { NodeServerTrace.Trace.TraceEvent(TraceEventType.Warning, 0, "Unknown command received : " + Command); } object payload = _PayloadObject; payloadStream.ReadWrite(payloadType, ref payload); if (unknown) { ((UnknowPayload)payload)._Command = Command; } Payload = (Payload)payload; } }
// We use this for big blocks, because the default array pool would allocate a new array. We do not need lot's of bucket such arrays are short lived. //readonly static Lazy<ArrayPool<byte>> BigArrayPool = new Lazy<ArrayPool<byte>>(() => ArrayPool<byte>.Create(0x02000000, 5), false); //ArrayPool<byte> GetArrayPool(int size) => size < 1_048_576 ? ArrayPool<byte>.Shared : BigArrayPool.Value; public void ReadWrite(BitcoinStream stream) { if (Payload == null && stream.Serializing) { throw new InvalidOperationException("Payload not affected"); } if (stream.Serializing || (!stream.Serializing && !_SkipMagic)) { stream.ReadWrite(ref magic); } stream.ReadWrite(ref command); if (stream.Serializing) { // We can optimize by calculating the length at the same time we calculate the checksum if (stream.ProtocolCapabilities.SupportCheckSum) { var hashStream = stream.ProtocolCapabilities.GetChecksumHashStream(); var bsStream = new BitcoinStream(hashStream, true); bsStream.CopyParameters(stream); Payload.ReadWrite(bsStream); var length = (int)bsStream.Counter.WrittenBytes; var checksum = hashStream.GetHash().GetLow32(); stream.ReadWrite(ref length); stream.ReadWrite(ref checksum); } else { var bitcoinStream = new BitcoinStream(Stream.Null, true); bitcoinStream.CopyParameters(stream); Payload.ReadWrite(bitcoinStream); var length = (int)bitcoinStream.Counter.WrittenBytes; stream.ReadWrite(ref length); } stream.ReadWrite(Payload); } else { int length = 0; stream.ReadWrite(ref length); if (length < 0 || length > 0x02000000) //MAX_SIZE 0x02000000 Serialize.h { throw new FormatException("Message payload too big ( > 0x02000000 bytes)"); } //var arrayPool = GetArrayPool(length); var payloadBytes = new byte[length]; // arrayPool.Rent(length); try { uint expectedChecksum = 0; if (stream.ProtocolCapabilities.SupportCheckSum) { stream.ReadWrite(ref expectedChecksum); } stream.ReadWrite(ref payloadBytes, 0, length); // We do not verify the checksum anymore because for 1000 blocks, it takes 80 seconds. BitcoinStream payloadStream = new BitcoinStream(new MemoryStream(payloadBytes, 0, length, false), false); payloadStream.CopyParameters(stream); var payloadType = PayloadAttribute.GetCommandType(Command); var unknown = payloadType == typeof(UnknowPayload); if (unknown) { Logs.NodeServer.LogWarning("Unknown command received {command}", Command); } IBitcoinSerializable payload = null; if (!stream.ConsensusFactory.TryCreateNew(payloadType, out payload)) { payload = (IBitcoinSerializable)Activator.CreateInstance(payloadType); } payload.ReadWrite(payloadStream); if (unknown) { ((UnknowPayload)payload)._Command = Command; } Payload = (Payload)payload; } finally { payloadBytes = null; // arrayPool.Return(payloadBytes); } } }