Esempio n. 1
0
        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>()
            }));
        }
Esempio n. 3
0
        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();
        }
Esempio n. 4
0
        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();
            }
        }
Esempio n. 5
0
        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)
                });
            }
        }
Esempio n. 6
0
        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);
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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)
                });
            }
        }
Esempio n. 9
0
        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)
                });
            }
        }