Exemplo n.º 1
0
        private void SignAndRelay(ConsensusPayload payload)
        {
            SignatureContext sc;

            try
            {
                sc = new SignatureContext(payload);
            }
            catch (InvalidOperationException)
            {
                return;
            }
            wallet.Sign(sc);
            sc.Signable.Scripts = sc.GetScripts();
            localNode.RelayDirectly(payload);
        }
Exemplo n.º 2
0
        private void SignAndRelay(ConsensusPayload payload)
        {
            ContractParametersContext sc;

            try
            {
                sc = new ContractParametersContext(payload);
                wallet.Sign(sc);
            }
            catch (InvalidOperationException)
            {
                return;
            }
            sc.Verifiable.Scripts = sc.GetScripts();
            localNode.RelayDirectly(payload);
        }
Exemplo n.º 3
0
        private ConsensusPayload MakeSignedPayload(ConsensusMessage message)
        {
            message.ViewNumber = ViewNumber;
            ConsensusPayload payload = new ConsensusPayload
            {
                Version        = Version,
                PrevHash       = PrevHash,
                BlockIndex     = BlockIndex,
                ValidatorIndex = (ushort)MyIndex,
                Timestamp      = Timestamp,
                Data           = message.ToArray()
            };

            SignPayload(payload);
            return(payload);
        }
Exemplo n.º 4
0
        private void SignAndRelay(ConsensusPayload payload)
        {
            ContractParametersContext sc;

            try
            {
                sc = new ContractParametersContext(payload);
                wallet.Sign(sc);
            }
            catch (InvalidOperationException)
            {
                return;
            }
            sc.Verifiable.Witnesses = sc.GetWitnesses();
            system.LocalNode.Tell(new LocalNode.SendDirectly {
                Inventory = payload
            });
        }
Exemplo n.º 5
0
 private void OnPrepareResponseReceived(ConsensusPayload payload, PrepareResponse message)
 {
     if (context.Signatures[payload.ValidatorIndex] != null)
     {
         return;
     }
     Log($"{nameof(OnPrepareResponseReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex}");
     byte[] hashData = context.MakeHeader()?.GetHashData();
     if (hashData == null)
     {
         context.Signatures[payload.ValidatorIndex] = message.Signature;
     }
     else if (Crypto.Default.VerifySignature(hashData, message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false)))
     {
         context.Signatures[payload.ValidatorIndex] = message.Signature;
         CheckSignatures();
     }
 }
Exemplo n.º 6
0
 private void OnCommitReceived(ConsensusPayload payload, Commit commit)
 {
     if (context.CommitPayloads[payload.ValidatorIndex] != null)
     {
         return;
     }
     Log($"{nameof(OnCommitReceived)}: height={payload.BlockIndex} view={commit.ViewNumber} index={payload.ValidatorIndex}");
     byte[] hashData = context.MakeHeader()?.GetHashData();
     if (hashData == null)
     {
         context.CommitPayloads[payload.ValidatorIndex] = payload;
     }
     else if (Crypto.Default.VerifySignature(hashData, commit.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false)))
     {
         context.CommitPayloads[payload.ValidatorIndex] = payload;
         CheckCommits();
     }
 }
Exemplo n.º 7
0
 private void OnChangeViewReceived(ConsensusPayload payload, ChangeView message)
 {
     Log($"{nameof(OnChangeViewReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} nv={message.NewViewNumber}");
     if (message.NewViewNumber == 0xFF)
     {
         // New Start and Restart ChangeViewing.
         InitializeConsensus(0);
     }
     else
     {
         if (message.NewViewNumber <= context.ExpectedView[payload.ValidatorIndex])
         {
             return;
         }
         context.ExpectedView[payload.ValidatorIndex] = message.NewViewNumber;
         CheckExpectedView(message.NewViewNumber);
     }
 }
Exemplo n.º 8
0
        private void OnPerpareRequestReceived(ConsensusPayload payload, PerpareRequest message)
        {
            Log($"{nameof(OnPerpareRequestReceived)} h:{payload.Height} v:{message.ViewNumber} i:{payload.MinerIndex} tx:{message.TransactionHashes.Length}");
            if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived))
            {
                return;
            }
            if (payload.MinerIndex != 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.TransactionHashes = message.TransactionHashes;
            context.Transactions      = new Dictionary <UInt256, Transaction>();
            if (!context.MakeHeader().VerifySignature(context.Miners[payload.MinerIndex], message.Signature))
            {
                return;
            }
            context.Signatures[payload.MinerIndex] = message.Signature;
            if (!AddTransaction(message.MinerTransaction))
            {
                return;
            }
            Dictionary <UInt256, Transaction> mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash);

            foreach (UInt256 hash in context.TransactionHashes.Skip(1))
            {
                if (mempool.ContainsKey(hash))
                {
                    if (!AddTransaction(mempool[hash]))
                    {
                        return;
                    }
                }
            }
        }
Exemplo n.º 9
0
        private void LocalNode_InventoryReceived(object sender, IInventory inventory)
        {
            ConsensusPayload payload = inventory as ConsensusPayload;

            if (payload != null)
            {
                lock (context)
                {
                    if (payload.ValidatorIndex == context.MyIndex)
                    {
                        return;
                    }
                    if (payload.Version != ConsensusContext.Version || payload.PrevHash != context.PrevHash || payload.BlockIndex != context.BlockIndex)
                    {
                        return;
                    }
                    if (payload.ValidatorIndex >= context.Validators.Length)
                    {
                        return;
                    }
                    ConsensusMessage message = ConsensusMessage.DeserializeFrom(payload.Data);
                    if (message.ViewNumber != context.ViewNumber && message.Type != ConsensusMessageType.ChangeView)
                    {
                        return;
                    }
                    switch (message.Type)
                    {
                    case ConsensusMessageType.ChangeView:
                        OnChangeViewReceived(payload, (ChangeView)message);
                        break;

                    case ConsensusMessageType.PerpareRequest:
                        OnPerpareRequestReceived(payload, (PerpareRequest)message);
                        break;

                    case ConsensusMessageType.PerpareResponse:
                        OnPerpareResponseReceived(payload, (PerpareResponse)message);
                        break;
                    }
                }
            }
        }
Exemplo n.º 10
0
        private IVerifiable deserializeContainer(dynamic args)
        {
            byte[]      serializedContainer = (byte[])args.buffer;
            string      typeIn = (string)args.type;
            IVerifiable container;

            ContainerType type;

            if (Enum.TryParse <ContainerType>(typeIn, out type))
            {
                switch (type)
                {
                case ContainerType.Block:
                    container = new Block();
                    break;

                case ContainerType.Transaction:
                    container = new Transaction();
                    break;

                case ContainerType.Signers:
                    container = new Signers();
                    break;

                case ContainerType.ConsensusPayload:
                    container = new ConsensusPayload();
                    break;

                default:
                    throw new ArgumentException($"{typeIn} is not a valid container type");
                }
                using (MemoryStream ms = new MemoryStream(serializedContainer))
                    using (BinaryReader reader = new BinaryReader(ms))
                    {
                        container.Deserialize(reader);
                    }

                return(container);
            }

            throw new ArgumentException($"{typeIn} is not a valid container type");
        }
            public static PreparationPayloadCompact FromPayload(ConsensusPayload payload)
            {
                byte[]           StateRootSignature = Array.Empty <byte>();
                ConsensusMessage message            = payload.ConsensusMessage;

                if (message is PrepareRequest req)
                {
                    StateRootSignature = req.StateRootSignature;
                }
                else if (message is PrepareResponse resp)
                {
                    StateRootSignature = resp.StateRootSignature;
                }
                return(new PreparationPayloadCompact
                {
                    ValidatorIndex = payload.ValidatorIndex,
                    InvocationScript = payload.Witness.InvocationScript,
                    StateRootSignature = StateRootSignature
                });
            }
Exemplo n.º 12
0
        private void SignAndRelay(ConsensusPayload payload)
        {
            ReportNeoBlockchain reportObj = new ReportNeoBlockchain("[NeoConsensusService-SignAndRelay]");

            ContractParametersContext sc;

            try
            {
                sc = new ContractParametersContext(payload);
                wallet.Sign(sc);
            }
            catch (InvalidOperationException)
            {
                return;
            }
            sc.Verifiable.Scripts = sc.GetScripts();
            localNode.RelayDirectly(payload);

            reportObj.appendElapsedTime();
        }
Exemplo n.º 13
0
        private void OnPerpareResponseReceived(ConsensusPayload payload, PerpareResponse message)
        {
            Log($"{nameof(OnPerpareResponseReceived)} h:{payload.Height} v:{message.ViewNumber} i:{payload.MinerIndex}");
            if (context.State.HasFlag(ConsensusState.BlockSent))
            {
                return;
            }
            if (context.Signatures[payload.MinerIndex] != null)
            {
                return;
            }
            Block header = context.MakeHeader();

            if (header == null || !header.VerifySignature(context.Miners[payload.MinerIndex], message.Signature))
            {
                return;
            }
            context.Signatures[payload.MinerIndex] = message.Signature;
            CheckSignatures();
        }
Exemplo n.º 14
0
 internal ConsensusPayload[] GetChangeViewPayloads(ConsensusContext context, ConsensusPayload payload)
 {
     return(ChangeViewMessages.Values.Select(p => new ConsensusPayload
     {
         Version = payload.Version,
         PrevHash = payload.PrevHash,
         BlockIndex = payload.BlockIndex,
         ValidatorIndex = p.ValidatorIndex,
         ConsensusMessage = new ChangeView
         {
             ViewNumber = p.OriginalViewNumber,
             Timestamp = p.Timestamp
         },
         Witness = new Witness
         {
             InvocationScript = p.InvocationScript,
             VerificationScript = Contract.CreateSignatureRedeemScript(context.Validators[p.ValidatorIndex])
         }
     }).ToArray());
 }
Exemplo n.º 15
0
        private void OnPrepareResponseReceived(ConsensusPayload payload, PrepareResponse message)
        {
            Log($"{nameof(OnPrepareResponseReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex}");
            if (context.State.HasFlag(ConsensusState.BlockSent))
            {
                return;
            }
            if (context.Signatures[payload.ValidatorIndex] != null)
            {
                return;
            }
            Block header = context.MakeHeader();

            if (header == null || !Crypto.Default.VerifySignature(header.GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false)))
            {
                return;
            }
            context.Signatures[payload.ValidatorIndex] = message.Signature;
            CheckSignatures();
        }
Exemplo n.º 16
0
 private void OnPrepareResponseReceived(ConsensusPayload payload, PrepareResponse message)
 {
     if (context.PreparationPayloads[payload.ValidatorIndex] != null)
     {
         return;
     }
     if (context.PreparationPayloads[context.PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[context.PrimaryIndex].Hash))
     {
         return;
     }
     Log($"{nameof(OnPrepareResponseReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex}");
     context.PreparationPayloads[payload.ValidatorIndex] = payload;
     if (context.CommitSent())
     {
         return;
     }
     if (context.RequestSentOrReceived())
     {
         CheckPreparations();
     }
 }
Exemplo n.º 17
0
        private void OnInventory(IInventory inventory, bool relay = true)
        {
            RelayResult rr = new RelayResult
            {
                Inventory = inventory,
                Result    = inventory switch
                {
                    Block block => OnNewBlock(block),
                    Transaction transaction => OnNewTransaction(transaction),
                    ConsensusPayload payload => OnNewConsensus(payload),
                    _ => VerifyResult.Unknown
                }
            };

            if (relay && rr.Result == VerifyResult.Succeed)
            {
                system.LocalNode.Tell(new LocalNode.RelayDirectly {
                    Inventory = inventory
                });
            }
            Context.System.EventStream.Publish(rr);
        }
Exemplo n.º 18
0
        private void CheckPreparations()
        {
            if (context.PreparationPayloads.Count(p => p != null) >= context.M() && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p)))
            {
                ConsensusPayload payload = context.MakeCommit();
                Log($"send commit");
                context.Save();
                localNode.Tell(new LocalNode.SendDirectly {
                    Inventory = payload
                });
                // Set timer, so we will resend the commit in case of a networking issue
                ChangeTimer(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock));

                StateRoot stateRoot = context.CreateStateRoot();
                Log($"relay stateRoot: height={stateRoot.Index} hash={stateRoot.Root}");
                localNode.Tell(new LocalNode.Relay {
                    Inventory = stateRoot
                });

                CheckCommits();
            }
        }
Exemplo n.º 19
0
        private void OnChangeViewReceived(ConsensusPayload payload, ChangeView message)
        {
            if (message.NewViewNumber <= context.ViewNumber)
            {
                OnRecoveryRequestReceived(payload);
            }

            if (context.CommitSent)
            {
                return;
            }

            var expectedView = context.ChangeViewPayloads[payload.ValidatorIndex]?.GetDeserializedMessage <ChangeView>().NewViewNumber ?? (byte)0;

            if (message.NewViewNumber <= expectedView)
            {
                return;
            }

            Log($"{nameof(OnChangeViewReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} nv={message.NewViewNumber} reason={message.Reason}");
            context.ChangeViewPayloads[payload.ValidatorIndex] = payload;
            CheckExpectedView(message.NewViewNumber);
        }
Exemplo n.º 20
0
 internal ConsensusPayload GetPrepareRequestPayload(ConsensusContext context, ConsensusPayload payload)
 {
     if (PrepareRequestMessage == null)
     {
         return(null);
     }
     if (!PreparationMessages.TryGetValue((int)context.Block.ConsensusData.PrimaryIndex, out RecoveryMessage.PreparationPayloadCompact compact))
     {
         return(null);
     }
     return(new ConsensusPayload
     {
         Version = payload.Version,
         PrevHash = payload.PrevHash,
         BlockIndex = payload.BlockIndex,
         ValidatorIndex = (ushort)context.Block.ConsensusData.PrimaryIndex,
         ConsensusMessage = PrepareRequestMessage,
         Witness = new Witness
         {
             InvocationScript = compact.InvocationScript,
             VerificationScript = Contract.CreateSignatureRedeemScript(context.Validators[context.Block.ConsensusData.PrimaryIndex])
         }
     });
 }
Exemplo n.º 21
0
        private void LocalNode_InventoryReceived(object sender, IInventory inventory)
        {
            ConsensusPayload payload = inventory as ConsensusPayload;

            if (payload != null)
            {
                lock (context)
                {
                    if (payload.ValidatorIndex == context.MyIndex)
                    {
                        return;
                    }

                    if (payload.Version != ConsensusContext.Version)
                    {
                        return;
                    }
                    if (payload.PrevHash != context.PrevHash || payload.BlockIndex != context.BlockIndex)
                    {
                        // Request blocks

                        if (Blockchain.Default?.Height + 1 < payload.BlockIndex)
                        {
                            Log($"chain sync: expected={payload.BlockIndex} current: {Blockchain.Default?.Height}");

                            localNode.RequestGetBlocks();
                        }

                        return;
                    }

                    if (payload.ValidatorIndex >= context.Validators.Length)
                    {
                        return;
                    }
                    ConsensusMessage message;
                    try
                    {
                        message = ConsensusMessage.DeserializeFrom(payload.Data);
                    }
                    catch
                    {
                        return;
                    }
                    if (message.ViewNumber != context.ViewNumber && message.Type != ConsensusMessageType.ChangeView)
                    {
                        return;
                    }
                    switch (message.Type)
                    {
                    case ConsensusMessageType.ChangeView:
                        OnChangeViewReceived(payload, (ChangeView)message);
                        break;

                    case ConsensusMessageType.PrepareRequest:
                        OnPrepareRequestReceived(payload, (PrepareRequest)message);
                        break;

                    case ConsensusMessageType.PrepareResponse:
                        OnPrepareResponseReceived(payload, (PrepareResponse)message);
                        break;
                    }
                }
            }
        }
Exemplo n.º 22
0
        private void LocalNode_NewInventory(object sender, Inventory inventory)
        {
            ConsensusPayload payload = inventory as ConsensusPayload;

            if (payload != null)
            {
                lock (context)
                {
                    if (payload.MinerIndex == context.MinerIndex)
                    {
                        return;
                    }
                    if (payload.Version != ConsensusContext.Version || payload.PrevHash != context.PrevHash || payload.Height != context.Height)
                    {
                        return;
                    }
                    if (payload.MinerIndex >= context.Miners.Length)
                    {
                        return;
                    }
                    ConsensusMessage message = ConsensusMessage.DeserializeFrom(payload.Data);
                    if (message.ViewNumber != context.ViewNumber && message.Type != ConsensusMessageType.ChangeView)
                    {
                        return;
                    }
                    switch (message.Type)
                    {
                    case ConsensusMessageType.ChangeView:
                        OnChangeViewReceived(payload, (ChangeView)message);
                        break;

                    case ConsensusMessageType.PerpareRequest:
                        OnPerpareRequestReceived(payload, (PerpareRequest)message);
                        break;

                    case ConsensusMessageType.PerpareResponse:
                        OnPerpareResponseReceived(payload, (PerpareResponse)message);
                        break;
                    }
                }
            }
            Transaction tx = inventory as Transaction;

            if (tx != null)
            {
                lock (context)
                {
                    if (!context.State.HasFlag(ConsensusState.Backup) || !context.State.HasFlag(ConsensusState.RequestReceived) || context.State.HasFlag(ConsensusState.SignatureSent))
                    {
                        return;
                    }
                    if (context.Transactions.ContainsKey(tx.Hash))
                    {
                        return;
                    }
                    if (!context.TransactionHashes.Contains(tx.Hash))
                    {
                        return;
                    }
                    AddTransaction(tx);
                }
            }
        }
Exemplo n.º 23
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)
                });
            }
        }
Exemplo n.º 24
0
 internal ConsensusPayload[] GetCommitPayloadsFromRecoveryMessage(ConsensusContext context, ConsensusPayload payload)
 {
     return(CommitMessages.Values.Select(p => new ConsensusPayload
     {
         Version = payload.Version,
         PrevHash = payload.PrevHash,
         BlockIndex = payload.BlockIndex,
         ValidatorIndex = p.ValidatorIndex,
         ConsensusMessage = new Commit
         {
             ViewNumber = p.ViewNumber,
             Signature = p.Signature
         },
         Witness = new Witness
         {
             InvocationScript = p.InvocationScript,
             VerificationScript = Contract.CreateSignatureRedeemScript(context.Validators[p.ValidatorIndex])
         }
     }).ToArray());
 }
Exemplo n.º 25
0
        internal ConsensusPayload[] GetPrepareResponsePayloads(ConsensusContext context, ConsensusPayload payload)
        {
            UInt256 preparationHash = PreparationHash ?? context.PreparationPayloads[context.Block.ConsensusData.PrimaryIndex]?.Hash;

            if (preparationHash is null)
            {
                return(new ConsensusPayload[0]);
            }
            return(PreparationMessages.Values.Where(p => p.ValidatorIndex != context.Block.ConsensusData.PrimaryIndex).Select(p => new ConsensusPayload
            {
                Version = payload.Version,
                PrevHash = payload.PrevHash,
                BlockIndex = payload.BlockIndex,
                ValidatorIndex = p.ValidatorIndex,
                ConsensusMessage = new PrepareResponse
                {
                    ViewNumber = ViewNumber,
                    PreparationHash = preparationHash
                },
                Witness = new Witness
                {
                    InvocationScript = p.InvocationScript,
                    VerificationScript = Contract.CreateSignatureRedeemScript(context.Validators[p.ValidatorIndex])
                }
            }).ToArray());
        }
Exemplo n.º 26
0
        private void OnChangeViewReceived(ConsensusPayload payload, ChangeView message)
        {
            // We keep track of the payload hashes received in this block, and don't respond with recovery
            // in response to the same payload that we already responded to previously.
            // ChangeView messages include a Timestamp when the change view is sent, thus if a node restarts
            // and issues a change view for the same view, it will have a different hash and will correctly respond
            // again; however replay attacks of the ChangeView message from arbitrary nodes will not trigger an
            // additional recovery message response.
            if (!knownHashes.Add(payload.Hash))
            {
                return;
            }
            if (message.NewViewNumber <= context.ViewNumber)
            {
                if (context.WatchOnly())
                {
                    return;
                }
                if (!context.CommitSent())
                {
                    bool shouldSendRecovery = false;
                    // Limit recovery to be sent from, at least, `f` nodes when the request is from a lower view number.
                    int allowedRecoveryNodeCount = context.F();
                    for (int i = 0; i < allowedRecoveryNodeCount; i++)
                    {
                        var eligibleResponders = context.Validators.Length - 1;
                        var chosenIndex        = (payload.ValidatorIndex + i + message.NewViewNumber) % eligibleResponders;
                        if (chosenIndex >= payload.ValidatorIndex)
                        {
                            chosenIndex++;
                        }
                        if (chosenIndex != context.MyIndex)
                        {
                            continue;
                        }
                        shouldSendRecovery = true;
                        break;
                    }

                    if (!shouldSendRecovery)
                    {
                        return;
                    }
                }
                Log($"send recovery from view: {message.ViewNumber} to view: {context.ViewNumber}");
                localNode.Tell(new LocalNode.SendDirectly {
                    Inventory = context.MakeRecoveryMessage()
                });
            }

            if (context.CommitSent())
            {
                return;
            }

            var expectedView = context.ChangeViewPayloads[payload.ValidatorIndex]?.GetDeserializedMessage <ChangeView>().NewViewNumber ?? (byte)0;

            if (message.NewViewNumber <= expectedView)
            {
                return;
            }

            Log($"{nameof(OnChangeViewReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} nv={message.NewViewNumber}");
            context.ChangeViewPayloads[payload.ValidatorIndex] = payload;
            CheckExpectedView(message.NewViewNumber);
        }
Exemplo n.º 27
0
        public void ConsensusService_Primary_Sends_PrepareRequest_After_OnStart()
        {
            TestProbe subscriber = CreateTestProbe();

            var mockConsensusContext = new Mock <IConsensusContext>();
            var mockStore            = new Mock <Store>();

            // context.Reset(): do nothing
            //mockConsensusContext.Setup(mr => mr.Reset()).Verifiable(); // void
            mockConsensusContext.SetupGet(mr => mr.MyIndex).Returns(2); // MyIndex == 2
            mockConsensusContext.SetupGet(mr => mr.BlockIndex).Returns(2);
            mockConsensusContext.SetupGet(mr => mr.PrimaryIndex).Returns(2);
            mockConsensusContext.SetupGet(mr => mr.ViewNumber).Returns(0);
            mockConsensusContext.SetupProperty(mr => mr.Nonce);
            mockConsensusContext.SetupProperty(mr => mr.NextConsensus);
            mockConsensusContext.Object.NextConsensus = UInt160.Zero;
            mockConsensusContext.SetupGet(mr => mr.PreparationPayloads).Returns(new ConsensusPayload[7]);
            mockConsensusContext.SetupGet(mr => mr.CommitPayloads).Returns(new ConsensusPayload[7]);

            int timeIndex  = 0;
            var timeValues = new[] {
                //new DateTime(1968, 06, 01, 0, 0, 15, DateTimeKind.Utc), // For tests here
                new DateTime(1968, 06, 01, 0, 0, 1, DateTimeKind.Utc),                               // For receiving block
                new DateTime(1968, 06, 01, 0, 0, (int)Blockchain.SecondsPerBlock, DateTimeKind.Utc), // For Initialize
                new DateTime(1968, 06, 01, 0, 0, 15, DateTimeKind.Utc),                              // unused
                new DateTime(1968, 06, 01, 0, 0, 15, DateTimeKind.Utc)                               // unused
            };

            //TimeProvider.Current.UtcNow.ToTimestamp().Should().Be(4244941711); //1968-06-01 00:00:15

            Console.WriteLine($"time 0: {timeValues[0].ToString()} 1: {timeValues[1].ToString()} 2: {timeValues[2].ToString()} 3: {timeValues[3].ToString()}");

            //mockConsensusContext.Object.block_received_time = new DateTime(1968, 06, 01, 0, 0, 1, DateTimeKind.Utc);
            //mockConsensusContext.Setup(mr => mr.GetUtcNow()).Returns(new DateTime(1968, 06, 01, 0, 0, 15, DateTimeKind.Utc));

            var timeMock = new Mock <TimeProvider>();

            timeMock.SetupGet(tp => tp.UtcNow).Returns(() => timeValues[timeIndex])
            .Callback(() => timeIndex++);
            //new DateTime(1968, 06, 01, 0, 0, 15, DateTimeKind.Utc));
            TimeProvider.Current = timeMock.Object;

            //public void Log(string message, LogLevel level)
            // TODO: create ILogPlugin for Tests

            /*
             * mockConsensusContext.Setup(mr => mr.Log(It.IsAny<string>(), It.IsAny<LogLevel>()))
             *           .Callback((string message, LogLevel level) => {
             *                           Console.WriteLine($"CONSENSUS LOG: {message}");
             *                                                     }
             *                    );
             */

            // Creating proposed block
            Header header = new Header();

            TestUtils.SetupHeaderWithValues(header, UInt256.Zero, out UInt256 merkRootVal, out UInt160 val160, out uint timestampVal, out uint indexVal, out ulong consensusDataVal, out Witness scriptVal);
            header.Size.Should().Be(109);

            Console.WriteLine($"header {header} hash {header.Hash} timstamp {timestampVal}");

            timestampVal.Should().Be(4244941696); //1968-06-01 00:00:00
                                                  // check basic ConsensusContext
            mockConsensusContext.Object.MyIndex.Should().Be(2);
            //mockConsensusContext.Object.block_received_time.ToTimestamp().Should().Be(4244941697); //1968-06-01 00:00:01

            MinerTransaction minerTx = new MinerTransaction
            {
                Attributes = new TransactionAttribute[0],
                Inputs     = new CoinReference[0],
                Outputs    = new TransactionOutput[0],
                Witnesses  = new Witness[0],
                Nonce      = 42
            };

            PrepareRequest prep = new PrepareRequest
            {
                Nonce             = mockConsensusContext.Object.Nonce,
                NextConsensus     = mockConsensusContext.Object.NextConsensus,
                TransactionHashes = new UInt256[0],
                MinerTransaction  = minerTx //(MinerTransaction)Transactions[TransactionHashes[0]],
            };

            ConsensusPayload prepPayload = new ConsensusPayload
            {
                Version          = 0,
                PrevHash         = mockConsensusContext.Object.PrevHash,
                BlockIndex       = mockConsensusContext.Object.BlockIndex,
                ValidatorIndex   = (ushort)mockConsensusContext.Object.MyIndex,
                ConsensusMessage = prep
            };

            mockConsensusContext.Setup(mr => mr.MakePrepareRequest()).Returns(prepPayload);

            // ============================================================================
            //                      creating ConsensusService actor
            // ============================================================================

            TestActorRef <ConsensusService> actorConsensus = ActorOfAsTestActorRef <ConsensusService>(
                Akka.Actor.Props.Create(() => new ConsensusService(subscriber, subscriber, mockConsensusContext.Object))
                );

            Console.WriteLine("will trigger OnPersistCompleted!");
            actorConsensus.Tell(new Blockchain.PersistCompleted
            {
                Block = new Block
                {
                    Version       = header.Version,
                    PrevHash      = header.PrevHash,
                    MerkleRoot    = header.MerkleRoot,
                    Timestamp     = header.Timestamp,
                    Index         = header.Index,
                    ConsensusData = header.ConsensusData,
                    NextConsensus = header.NextConsensus
                }
            });

            // OnPersist will not launch timer, we need OnStart

            Console.WriteLine("will start consensus!");
            actorConsensus.Tell(new ConsensusService.Start());

            Console.WriteLine("OnTimer should expire!");
            Console.WriteLine("Waiting for subscriber message!");
            // Timer should expire in one second (block_received_time at :01, initialized at :02)

            var answer = subscriber.ExpectMsg <LocalNode.SendDirectly>();

            Console.WriteLine($"MESSAGE 1: {answer}");
            //var answer2 = subscriber.ExpectMsg<LocalNode.SendDirectly>(); // expects to fail!

            // ============================================================================
            //                      finalize ConsensusService actor
            // ============================================================================

            //Thread.Sleep(4000);
            Sys.Stop(actorConsensus);
            TimeProvider.ResetToDefault();

            Assert.AreEqual(1, 1);
        }
Exemplo n.º 28
0
        // Since ConensusContext's constructor is internal, it can't be used from neo-express.
        // CreatePreloadBlock replicates the following logic for creating an empty block with ConensusContext

        // var ctx = new Neo.Consensus.ConsensusContext(wallet, store);
        // ctx.Reset(0);
        // ctx.MakePrepareRequest();
        // ctx.MakeCommit();
        // ctx.Save();
        // Block block = ctx.CreateBlock();

        static Block CreatePreloadBlock(Neo.Wallets.Wallet wallet, Random random, Transaction?transaction = null)
        {
            using var snapshot = Blockchain.Singleton.GetSnapshot();
            var validators = snapshot.GetValidators();

            if (validators.Length != 1)
            {
                throw new InvalidOperationException("Preload only supported for single-node blockchains");
            }

            var amountNetFee = Block.CalculateNetFee(Enumerable.Empty <Transaction>());

            if (amountNetFee != Fixed8.Zero)
            {
                throw new InvalidOperationException("amountNetFee must be zero");
            }

            var keyPair   = wallet.GetAccount(validators[0]).GetKey();
            var prevHash  = snapshot.CurrentBlockHash;
            var prevBlock = snapshot.GetBlock(prevHash);
            var nonce     = NextNonce(random);

            var minerTx = new MinerTransaction
            {
                Nonce      = (uint)(nonce % (uint.MaxValue + 1ul)),
                Attributes = Array.Empty <TransactionAttribute>(),
                Inputs     = Array.Empty <CoinReference>(),
                Outputs    = Array.Empty <TransactionOutput>(),
                Witnesses  = Array.Empty <Witness>()
            };

            var blockTransactions = transaction == null ? new Transaction[] { minerTx } : new Transaction[] { minerTx, transaction };
            var txHashes          = blockTransactions.Select(tx => tx.Hash).ToArray();
            var merkleRoot        = MerkleTree.ComputeRoot(txHashes);
            var nextConsensus     = Blockchain.GetConsensusAddress(snapshot.GetValidators(blockTransactions).ToArray());
            var consensusData     = nonce;

            var block = new Block()
            {
                Version       = 0,
                PrevHash      = prevHash,
                MerkleRoot    = merkleRoot,
                Timestamp     = prevBlock.Timestamp + 1,
                Index         = prevBlock.Index + 1,
                ConsensusData = nonce,
                NextConsensus = nextConsensus,
                Transactions  = Array.Empty <Transaction>(),
            };

            var commit = new Neo.Consensus.Commit()
            {
                ViewNumber = 0,
                Signature  = block.Sign(keyPair)
            };
            var payload = new ConsensusPayload
            {
                Version        = 0,
                PrevHash       = prevHash,
                BlockIndex     = block.Index,
                ValidatorIndex = (ushort)0,
                Data           = Neo.IO.Helper.ToArray(commit)
            };

            {
                var sc = new ContractParametersContext(payload);
                wallet.Sign(sc);
                payload.Witness = sc.GetWitnesses()[0];
            }

            {
                var      m                   = validators.Length - ((validators.Length - 1) / 3);
                Contract contract            = Contract.CreateMultiSigContract(m, validators);
                ContractParametersContext sc = new ContractParametersContext(block);
                for (int i = 0, j = 0; i < validators.Length && j < m; i++)
                {
                    sc.AddSignature(contract, validators[0], payload.GetDeserializedMessage <Neo.Consensus.Commit>().Signature);
                    j++;
                }
                block.Witness      = sc.GetWitnesses()[0];
                block.Transactions = blockTransactions;
            }
            return(block);
        }
Exemplo n.º 29
0
 private void OnCommitReceived(ConsensusPayload payload, Commit commit)
 {
     ref ConsensusPayload existingCommitPayload = ref context.CommitPayloads[payload.ValidatorIndex];
Exemplo n.º 30
0
        /// <summary>
        /// 收到议长共识请求
        /// </summary>
        /// <param name="payload">议长的共识参数</param>
        /// <param name="message"></param>
        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;      // 交易哈希
            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;
            // 将内存缓存的交易添加到共识的 context 中
            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))// 从缓存队列中读取添加到 context 中
                    {
                        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();
                LocalNode.AllowHashes(hashes);
                InvPayload msg = InvPayload.Create(InventoryType.TX, hashes);
                foreach (RemoteNode node in localNode.GetRemoteNodes())
                {
                    node.EnqueueMessage("getdata", msg);
                }
            }
        }