public ConsensusPayload MakeRecoveryMessage() { PrepareRequest prepareRequestMessage = null; if (TransactionHashes != null) { prepareRequestMessage = new PrepareRequest { ViewNumber = ViewNumber, TransactionHashes = TransactionHashes, Nonce = Nonce, NextConsensus = NextConsensus, MinerTransaction = (MinerTransaction)Transactions[TransactionHashes[0]], Timestamp = Timestamp }; } return(MakeSignedPayload(new RecoveryMessage() { ChangeViewMessages = LastChangeViewPayloads.Where(p => p != null).Select(p => RecoveryMessage.ChangeViewPayloadCompact.FromPayload(p)).Take(this.M()).ToDictionary(p => (int)p.ValidatorIndex), PrepareRequestMessage = prepareRequestMessage, // We only need a PreparationHash set if we don't have the PrepareRequest information. PreparationHash = TransactionHashes == null ? PreparationPayloads.Where(p => p != null).GroupBy(p => p.GetDeserializedMessage <PrepareResponse>().PreparationHash, (k, g) => new { Hash = k, Count = g.Count() }).OrderByDescending(p => p.Count).Select(p => p.Hash).FirstOrDefault() : null, PreparationMessages = PreparationPayloads.Where(p => p != null).Select(p => RecoveryMessage.PreparationPayloadCompact.FromPayload(p)).ToDictionary(p => (int)p.ValidatorIndex), CommitMessages = this.CommitSent() ? CommitPayloads.Where(p => p != null).Select(p => RecoveryMessage.CommitPayloadCompact.FromPayload(p)).ToDictionary(p => (int)p.ValidatorIndex) : new Dictionary <int, RecoveryMessage.CommitPayloadCompact>() })); }
public ExtensiblePayload MakeRecoveryMessage() { PrepareRequest prepareRequestMessage = null; if (TransactionHashes != null) { prepareRequestMessage = new PrepareRequest { Version = Block.Version, PrevHash = Block.PrevHash, ViewNumber = ViewNumber, Timestamp = Block.Timestamp, BlockIndex = Block.Index, Nonce = Block.ConsensusData.Nonce, TransactionHashes = TransactionHashes }; } return(MakeSignedPayload(new RecoveryMessage() { ChangeViewMessages = LastChangeViewPayloads.Where(p => p != null).Select(p => GetChangeViewPayloadCompact(p)).Take(M).ToDictionary(p => (int)p.ValidatorIndex), PrepareRequestMessage = prepareRequestMessage, // We only need a PreparationHash set if we don't have the PrepareRequest information. PreparationHash = TransactionHashes == null ? PreparationPayloads.Where(p => p != null).GroupBy(p => GetMessage <PrepareResponse>(p).PreparationHash, (k, g) => new { Hash = k, Count = g.Count() }).OrderByDescending(p => p.Count).Select(p => p.Hash).FirstOrDefault() : null, PreparationMessages = PreparationPayloads.Where(p => p != null).Select(p => GetPreparationPayloadCompact(p)).ToDictionary(p => (int)p.ValidatorIndex), CommitMessages = CommitSent ? CommitPayloads.Where(p => p != null).Select(p => GetCommitPayloadCompact(p)).ToDictionary(p => (int)p.ValidatorIndex) : new Dictionary <int, CommitPayloadCompact>() })); }
private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message) { TR.Enter(); Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived)) { TR.Exit(); return; } if (payload.ValidatorIndex != context.PrimaryIndex) { return; } if (payload.Timestamp <= Blockchain.Default.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp()) { Log($"Timestamp incorrect: {payload.Timestamp}"); TR.Exit(); return; } context.State |= ConsensusState.RequestReceived; context.Timestamp = payload.Timestamp; context.Nonce = message.Nonce; context.NextConsensus = message.NextConsensus; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary <UInt256, Transaction>(); if (!Crypto.Default.VerifySignature(context.MakeHeader().GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false))) { TR.Exit(); return; } context.Signatures = new byte[context.Validators.Length][]; context.Signatures[payload.ValidatorIndex] = message.Signature; Dictionary <UInt256, Transaction> mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash); foreach (UInt256 hash in context.TransactionHashes.Skip(1)) { if (mempool.TryGetValue(hash, out Transaction tx)) { if (!AddTransaction(tx, false)) { TR.Exit(); return; } } } if (!AddTransaction(message.MinerTransaction, true)) { TR.Exit(); return; } if (context.Transactions.Count < context.TransactionHashes.Length) { UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); LocalNode.AllowHashes(hashes); InvPayload msg = InvPayload.Create(InventoryType.TX, hashes); foreach (RemoteNode node in localNode.GetRemoteNodes()) { node.EnqueueMessage("getdata", msg); } } TR.Exit(); }
private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message) { Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived)) { return; } if (payload.ValidatorIndex != context.PrimaryIndex) { return; } if (payload.Timestamp <= Blockchain.Default.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp()) { Log($"Timestamp incorrect: {payload.Timestamp}"); return; } context.State |= ConsensusState.RequestReceived; context.Timestamp = payload.Timestamp; context.Nonce = message.Nonce; context.NextConsensus = message.NextConsensus; context.TransactionHashes = message.TransactionHashes; if (context.TransactionHashes.Length > Settings.Default.MaxTransactionsPerBlock) { return; } context.Transactions = new Dictionary <UInt256, Transaction>(); if (!Crypto.Default.VerifySignature(context.MakeHeader().GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false))) { return; } context.Signatures = new byte[context.Validators.Length][]; context.Signatures[payload.ValidatorIndex] = message.Signature; Dictionary <UInt256, Transaction> mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash); foreach (UInt256 hash in context.TransactionHashes.Skip(1)) { if (mempool.TryGetValue(hash, out Transaction tx)) { if (!AddTransaction(tx, false)) { return; } } } if (!AddTransaction(message.MinerTransaction, true)) { return; } LocalNode.AllowHashes(context.TransactionHashes.Except(context.Transactions.Keys)); if (context.Transactions.Count < context.TransactionHashes.Length) { localNode.SynchronizeMemoryPool(); } }
private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message) { Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived)) { return; } if (payload.ValidatorIndex != context.PrimaryIndex) { return; } if (payload.Timestamp <= context.Snapshot.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.UtcNow.AddMinutes(10).ToTimestamp()) { Log($"Timestamp incorrect: {payload.Timestamp}", LogLevel.Warning); return; } context.State |= ConsensusState.RequestReceived; context.Timestamp = payload.Timestamp; context.Nonce = message.Nonce; context.NextConsensus = message.NextConsensus; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary <UInt256, Transaction>(); if (!Crypto.Default.VerifySignature(context.MakeHeader().GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false))) { return; } context.Signatures = new byte[context.Validators.Length][]; context.Signatures[payload.ValidatorIndex] = message.Signature; Dictionary <UInt256, Transaction> mempool = Blockchain.Singleton.GetMemoryPool().ToDictionary(p => p.Hash); foreach (UInt256 hash in context.TransactionHashes.Skip(1)) { if (mempool.TryGetValue(hash, out Transaction tx)) { if (!AddTransaction(tx, false)) { return; } } } if (!AddTransaction(message.MinerTransaction, true)) { return; } if (context.Transactions.Count < context.TransactionHashes.Length) { UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); system.TaskManager.Tell(new TaskManager.RestartTasks { Payload = InvPayload.Create(InventoryType.TX, hashes) }); } }
public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); ChangeViewMessages = reader.ReadSerializableArray <ChangeViewPayloadCompact>(Blockchain.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); if (reader.ReadBoolean()) { PrepareRequestMessage = reader.ReadSerializable <PrepareRequest>(); } else { int preparationHashSize = UInt256.Zero.Size; if (preparationHashSize == (int)reader.ReadVarInt((ulong)preparationHashSize)) { PreparationHash = new UInt256(reader.ReadFixedBytes(preparationHashSize)); } } PreparationMessages = reader.ReadSerializableArray <PreparationPayloadCompact>(Blockchain.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); CommitMessages = reader.ReadSerializableArray <CommitPayloadCompact>(Blockchain.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); }
public override void Deserialize(ref MemoryReader reader) { base.Deserialize(ref reader); ChangeViewMessages = reader.ReadSerializableArray <ChangeViewPayloadCompact>(byte.MaxValue).ToDictionary(p => p.ValidatorIndex); if (reader.ReadBoolean()) { PrepareRequestMessage = reader.ReadSerializable <PrepareRequest>(); } else { int preparationHashSize = UInt256.Zero.Size; if (preparationHashSize == (int)reader.ReadVarInt((ulong)preparationHashSize)) { PreparationHash = new UInt256(reader.ReadMemory(preparationHashSize).Span); } } PreparationMessages = reader.ReadSerializableArray <PreparationPayloadCompact>(byte.MaxValue).ToDictionary(p => p.ValidatorIndex); CommitMessages = reader.ReadSerializableArray <CommitPayloadCompact>(byte.MaxValue).ToDictionary(p => p.ValidatorIndex); }
private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message) { if (context.State.HasFlag(ConsensusState.RequestReceived)) { return; } if (payload.ValidatorIndex != context.PrimaryIndex) { return; } Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (!context.State.HasFlag(ConsensusState.Backup)) { return; } if (payload.Timestamp <= context.PrevHeader.Timestamp || payload.Timestamp > TimeProvider.Current.UtcNow.AddMinutes(10).ToTimestamp()) { Log($"Timestamp incorrect: {payload.Timestamp}", LogLevel.Warning); return; } if (message.TransactionHashes.Any(p => context.TransactionExists(p))) { Log($"Invalid request: transaction already exists", LogLevel.Warning); return; } context.State |= ConsensusState.RequestReceived; context.Timestamp = payload.Timestamp; context.Nonce = message.Nonce; context.NextConsensus = message.NextConsensus; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary <UInt256, Transaction>(); byte[] hashData = context.MakeHeader().GetHashData(); if (!Crypto.Default.VerifySignature(hashData, message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false))) { return; } for (int i = 0; i < context.Signatures.Length; i++) { if (context.Signatures[i] != null) { if (!Crypto.Default.VerifySignature(hashData, context.Signatures[i], context.Validators[i].EncodePoint(false))) { context.Signatures[i] = null; } } } context.Signatures[payload.ValidatorIndex] = message.Signature; Dictionary <UInt256, Transaction> mempoolVerified = Blockchain.Singleton.MemPool.GetVerifiedTransactions().ToDictionary(p => p.Hash); List <Transaction> unverified = new List <Transaction>(); foreach (UInt256 hash in context.TransactionHashes.Skip(1)) { if (mempoolVerified.TryGetValue(hash, out Transaction tx)) { if (!AddTransaction(tx, false)) { return; } } else { if (Blockchain.Singleton.MemPool.TryGetValue(hash, out tx)) { unverified.Add(tx); } } } foreach (Transaction tx in unverified) { if (!AddTransaction(tx, true)) { return; } } if (!AddTransaction(message.MinerTransaction, true)) { return; } if (context.Transactions.Count < context.TransactionHashes.Length) { UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); taskManager.Tell(new TaskManager.RestartTasks { Payload = InvPayload.Create(InventoryType.TX, hashes) }); } }
private void OnPrepareRequestReceived(ExtensiblePayload payload, PrepareRequest message) { if (context.RequestSentOrReceived || context.NotAcceptingPayloadsDueToViewChanging) { return; } if (message.ValidatorIndex != context.Block.PrimaryIndex || message.ViewNumber != context.ViewNumber) { return; } if (message.Version != context.Block.Version || message.PrevHash != context.Block.PrevHash) { return; } if (message.TransactionHashes.Length > neoSystem.Settings.MaxTransactionsPerBlock) { return; } Log($"{nameof(OnPrepareRequestReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex} tx={message.TransactionHashes.Length}"); if (message.Timestamp <= context.PrevHeader.Timestamp || message.Timestamp > TimeProvider.Current.UtcNow.AddMilliseconds(8 * neoSystem.Settings.MillisecondsPerBlock).ToTimestampMS()) { Log($"Timestamp incorrect: {message.Timestamp}", LogLevel.Warning); return; } if (message.TransactionHashes.Any(p => NativeContract.Ledger.ContainsTransaction(context.Snapshot, p))) { Log($"Invalid request: transaction already exists", LogLevel.Warning); return; } // Timeout extension: prepare request has been received with success // around 2*15/M=30.0/5 ~ 40% block time (for M=5) ExtendTimerByFactor(2); context.Block.Header.Timestamp = message.Timestamp; context.Block.Header.Nonce = message.Nonce; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary <UInt256, Transaction>(); context.VerificationContext = new TransactionVerificationContext(); for (int i = 0; i < context.PreparationPayloads.Length; i++) { if (context.PreparationPayloads[i] != null) { if (!context.GetMessage <PrepareResponse>(context.PreparationPayloads[i]).PreparationHash.Equals(payload.Hash)) { context.PreparationPayloads[i] = null; } } } context.PreparationPayloads[message.ValidatorIndex] = payload; byte[] hashData = context.EnsureHeader().GetSignData(neoSystem.Settings.Network); for (int i = 0; i < context.CommitPayloads.Length; i++) { if (context.GetMessage(context.CommitPayloads[i])?.ViewNumber == context.ViewNumber) { if (!Crypto.VerifySignature(hashData, context.GetMessage <Commit>(context.CommitPayloads[i]).Signature.Span, context.Validators[i])) { context.CommitPayloads[i] = null; } } } if (context.TransactionHashes.Length == 0) { // There are no tx so we should act like if all the transactions were filled CheckPrepareResponse(); return; } Dictionary <UInt256, Transaction> mempoolVerified = neoSystem.MemPool.GetVerifiedTransactions().ToDictionary(p => p.Hash); List <Transaction> unverified = new List <Transaction>(); foreach (UInt256 hash in context.TransactionHashes) { if (mempoolVerified.TryGetValue(hash, out Transaction tx)) { if (!AddTransaction(tx, false)) { return; } } else { if (neoSystem.MemPool.TryGetValue(hash, out tx)) { unverified.Add(tx); } } } foreach (Transaction tx in unverified) { if (!AddTransaction(tx, true)) { return; } } if (context.Transactions.Count < context.TransactionHashes.Length) { UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); taskManager.Tell(new TaskManager.RestartTasks { Payload = InvPayload.Create(InventoryType.TX, hashes) }); } }