示例#1
0
        public bool SyncBlock(uint blockHeight)
        {
            TaskSession session = GetSyncSession(blockHeight, false);

            if (session == null)
            {
                return(false);
            }

            UInt256 hash = blockchain.GetBlockHash(blockHeight);

            if (hash == null)
            {
                return(false);
            }

            if (!globalTasks.Add(hash))
            {
                return(true);
            }

            AddSyncBlockTask(hash, blockHeight, session);
            session.RemoteNode.Tell(Message.Create(MessageType.GetData, InvPayload.Create(InventoryType.Block, hash)));
            session.RemoteNode.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Request, InventoryType.Block));

            syncingBlockHeight = blockHeight;
            Log($"SyncBlock:{blockHeight}, nodeId:{session.Version.NodeId}", LogLevel.Debug);
            return(true);
        }
示例#2
0
        private void CheckSyncBlockTimeout()
        {
            DateTime now = DateTime.UtcNow;

            SyncBlockTask[] timeoutTasks = syncBlockTasks.Values.SelectMany(p => p.Where(q => now >= q.ExpiryTime)).ToArray();
            foreach (SyncBlockTask task in timeoutTasks)
            {
                task.Session.Timeout++;
                task.Session.RemoteNode.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Timeout, InventoryType.Block));
                Log($"SyncBlock timeout:{task.BlockHeight}, nodeId:{task.Session.Version.NodeId}");

                if (task.BlockHeight <= blockchain.Height)
                {
                    RemoveSyncBlockTask(task);
                }
                else
                {
                    TaskSession session = GetSyncSession(task.BlockHeight, false);

                    if (session != null)
                    {
                        RestartSyncBlockTask(task, session);

                        session.RemoteNode.Tell(Message.Create(MessageType.GetData, InvPayload.Create(InventoryType.Block, task.Hash)));
                        session.RemoteNode.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Request, InventoryType.Block));
                    }
                    else
                    {
                        RemoveSyncBlockTask(task);
                    }
                }
            }
        }
示例#3
0
        private async Task OnGetBlocksMessageReceivedAsync(GetBlocksPayload payload)
        {
            if (!localNode.ServiceEnabled)
            {
                return;
            }
            if (Blockchain.Default == null)
            {
                return;
            }
            UInt256 hash = payload.HashStart.Select(p => new
            {
                Hash   = p,
                Height = Blockchain.Default.GetBlockHeight(p)
            }).Where(p => p.Height >= 0).OrderBy(p => p.Height).Select(p => p.Hash).FirstOrDefault();

            if (hash == null || hash == payload.HashStop)
            {
                return;
            }
            List <UInt256> hashes = new List <UInt256>();

            do
            {
                hash = Blockchain.Default.GetNextBlockHash(hash);
                if (hash == null)
                {
                    break;
                }
                hashes.Add(hash);
            } while (hash != payload.HashStop && hashes.Count < 500);
            await SendMessageAsync("inv", InvPayload.Create(InventoryType.MSG_BLOCK, hashes.ToArray()));
        }
示例#4
0
 private void OnInvMessageReceived(InvPayload payload)
 {
     if (payload.Type != InventoryType.TX && payload.Type != InventoryType.Block && payload.Type != InventoryType.Consensus)
     {
         return;
     }
     UInt256[] hashes = payload.Hashes.Distinct().ToArray();
     lock (LocalNode.KnownHashes)
     {
         hashes = hashes.Where(p => !LocalNode.KnownHashes.Contains(p)).ToArray();
     }
     if (hashes.Length == 0)
     {
         return;
     }
     lock (missions_global)
     {
         if (localNode.GlobalMissionsEnabled)
         {
             hashes = hashes.Where(p => !missions_global.Contains(p)).ToArray();
         }
         foreach (UInt256 hash in hashes)
         {
             missions_global.Add(hash);
             missions.Add(hash);
         }
     }
     if (hashes.Length == 0)
     {
         return;
     }
     EnqueueMessage("getdata", InvPayload.Create(payload.Type, hashes));
 }
示例#5
0
        private void OnInvMessageReceived(InvPayload payload)
        {
            UInt256[] hashes = payload.Hashes.Where(p => knownHashes.Add(p)).ToArray();
            if (hashes.Length == 0)
            {
                return;
            }
            switch (payload.Type)
            {
            case InventoryType.Block:
                using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot())
                    hashes = hashes.Where(p => !snapshot.ContainsBlock(p)).ToArray();
                break;

            case InventoryType.TX:
                using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot())
                    hashes = hashes.Where(p => !snapshot.ContainsTransaction(p)).ToArray();
                break;
            }
            if (hashes.Length == 0)
            {
                return;
            }
            system.TaskManager.Tell(new TaskManager.NewTasks {
                Payload = InvPayload.Create(payload.Type, hashes)
            }, Context.Parent);
        }
示例#6
0
        private bool OnBroadcastCommand(string[] args)
        {
            string        command = args[1].ToLower();
            ISerializable payload = null;

            switch (command)
            {
            case "addr":
                payload = AddrPayload.Create(NetworkAddressWithTime.Create(new IPEndPoint(IPAddress.Parse(args[2]), ushort.Parse(args[3])), NetworkAddressWithTime.NODE_NETWORK, DateTime.UtcNow.ToTimestamp()));
                break;

            case "block":
                if (args[2].Length == 64 || args[2].Length == 66)
                {
                    payload = Blockchain.Default.GetBlock(UInt256.Parse(args[2]));
                }
                else
                {
                    payload = Blockchain.Default.GetBlock(uint.Parse(args[2]));
                }
                break;

            case "getblocks":
            case "getheaders":
                payload = GetBlocksPayload.Create(UInt256.Parse(args[2]));
                break;

            case "getdata":
            case "inv":
                payload = InvPayload.Create(Enum.Parse <InventoryType>(args[2], true), args.Skip(3).Select(p => UInt256.Parse(p)).ToArray());
                break;

            case "tx":
                payload = LocalNode.GetTransaction(UInt256.Parse(args[2]));
                if (payload == null)
                {
                    payload = Blockchain.Default.GetTransaction(UInt256.Parse(args[2]));
                }
                break;

            case "alert":
            case "consensus":
            case "filteradd":
            case "filterload":
            case "headers":
            case "merkleblock":
            case "ping":
            case "pong":
            case "reject":
            case "verack":
            case "version":
                Console.WriteLine($"Command \"{command}\" is not supported.");
                return(true);
            }
            foreach (RemoteNode node in LocalNode.GetRemoteNodes())
            {
                node.EnqueueMessage(command, payload);
            }
            return(true);
        }
示例#7
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();
        }
示例#8
0
 private void OnInvMessageReceived(InvPayload payload)
 {
     InventoryVector[] vectors = payload.Inventories.Distinct().Where(p => Enum.IsDefined(typeof(InventoryType), p.Type)).ToArray();
     lock (LocalNode.KnownHashes)
     {
         vectors = vectors.Where(p => !LocalNode.KnownHashes.Contains(p.Hash)).ToArray();
     }
     if (vectors.Length == 0)
     {
         return;
     }
     lock (missions_global)
     {
         if (localNode.GlobalMissionsEnabled)
         {
             vectors = vectors.Where(p => !missions_global.Contains(p.Hash)).ToArray();
         }
         foreach (InventoryVector vector in vectors)
         {
             missions_global.Add(vector.Hash);
             missions.Add(vector.Hash);
         }
     }
     if (vectors.Length == 0)
     {
         return;
     }
     EnqueueMessage("getdata", InvPayload.Create(vectors));
 }
示例#9
0
        private void OnGetBlocksMessageReceived(GetBlocksPayload payload)
        {
            if (!localNode.ServiceEnabled)
            {
                return;
            }
            if (Blockchain.Default == null)
            {
                return;
            }
            UInt256 hash = payload.HashStart.Select(p => Blockchain.Default.GetHeader(p)).Where(p => p != null).OrderBy(p => p.Index).Select(p => p.Hash).FirstOrDefault();

            if (hash == null || hash == payload.HashStop)
            {
                return;
            }
            List <UInt256> hashes = new List <UInt256>();

            do
            {
                hash = Blockchain.Default.GetNextBlockHash(hash);
                if (hash == null)
                {
                    break;
                }
                hashes.Add(hash);
            } while (hash != payload.HashStop && hashes.Count < 500);
            EnqueueMessage("inv", InvPayload.Create(InventoryType.Block, hashes.ToArray()));
        }
示例#10
0
        private void RequestInventoryData(InventoryType type, UInt256[] hashes, IActorRef sender)
        {
            if (hashes.Length == 0)
            {
                return;
            }

            if (hashes.Length == 1)
            {
                sender.Tell(Message.Create(MessageType.GetData, InvPayload.Create(type, hashes[0])));
            }
            else
            {
                string cmd;
                if (type == InventoryType.Block)
                {
                    cmd = MessageType.GetBlk;
                }
                else if (type == InventoryType.TX)
                {
                    cmd = MessageType.GetTxn;
                }
                else
                {
                    return;
                }

                foreach (InvPayload group in InvPayload.CreateGroup(type, hashes))
                {
                    sender.Tell(Message.Create(cmd, group));
                }
            }

            Sender.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Request, type, hashes.Length));
        }
示例#11
0
        private void OnGetBlocksMessageReceived(GetBlocksPayload payload)
        {
            UInt256      hash = payload.HashStart;
            int          count = payload.Count <0 || payload.Count> InvPayload.MaxHashesCount ? InvPayload.MaxHashesCount : payload.Count;
            TrimmedBlock state = Blockchain.Singleton.Store.GetBlocks().TryGet(hash);

            if (state == null)
            {
                return;
            }
            List <UInt256> hashes = new List <UInt256>();

            for (uint i = 1; i <= count; i++)
            {
                uint index = state.Index + i;
                if (index > Blockchain.Singleton.Height)
                {
                    break;
                }
                hash = Blockchain.Singleton.GetBlockHash(index);
                if (hash == null)
                {
                    break;
                }
                hashes.Add(hash);
            }
            if (hashes.Count == 0)
            {
                return;
            }
            Context.Parent.Tell(Message.Create(MessageCommand.Inv, InvPayload.Create(InventoryType.Block, hashes.ToArray())));
        }
示例#12
0
        public void Size_Get()
        {
            var test = InvPayload.Create(InventoryType.TX, UInt256.Zero);

            test.Size.Should().Be(34);

            test = InvPayload.Create(InventoryType.TX, UInt256.Zero, UInt256.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00a4"));
            test.Size.Should().Be(66);
        }
示例#13
0
        public void DeserializeAndSerialize()
        {
            var test  = InvPayload.Create(InventoryType.TX, UInt256.Zero, UInt256.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00a4"));
            var clone = test.ToArray().AsSerializable <InvPayload>();

            Assert.AreEqual(test.Type, clone.Type);
            CollectionAssert.AreEqual(test.Hashes, clone.Hashes);

            Assert.ThrowsException <FormatException>(() => InvPayload.Create((InventoryType)0xff, UInt256.Zero).ToArray().AsSerializable <InvPayload>());
        }
示例#14
0
 private void InitializeConsensus(byte view_number)
 {
     lock (context)
     {
         if (view_number == 0)
         {
             context.Reset(wallet);
         }
         else
         {
             context.ChangeView(view_number);
         }
         if (context.MyIndex < 0)
         {
             return;
         }
         Log($"initialize: height={context.BlockIndex} view={view_number} index={context.MyIndex} role={(context.MyIndex == context.PrimaryIndex ? ConsensusState.Primary : ConsensusState.Backup)}");
         if (context.MyIndex == context.PrimaryIndex)
         {
             context.State |= ConsensusState.Primary;
             if (!context.State.HasFlag(ConsensusState.SignatureSent))
             {
                 FillContext();
             }
             if (context.TransactionHashes.Length > 1)
             {
                 InvPayload invPayload = InvPayload.Create(InventoryType.TX, context.TransactionHashes.Skip(1).ToArray());
                 foreach (RemoteNode node in localNode.GetRemoteNodes())
                 {
                     node.EnqueueMessage("inv", invPayload);
                 }
             }
             timer_height = context.BlockIndex;
             timer_view   = view_number;
             // 议长发起共识时间控制
             TimeSpan span = DateTime.Now - block_received_time;
             if (span >= Blockchain.TimePerBlock)
             {
                 timer.Change(0, Timeout.Infinite);// 间隔时间大于预订时间则立即发起共识
             }
             else
             {
                 timer.Change(Blockchain.TimePerBlock - span, Timeout.InfiniteTimeSpan);// 定时执行
             }
         }
         else
         {
             context.State = ConsensusState.Backup;
             timer_height  = context.BlockIndex;
             timer_view    = view_number;
             // 议员超时控制 t * 2 ^ (view_number + 1)
             timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (view_number + 1)), Timeout.InfiniteTimeSpan);
         }
     }
 }
示例#15
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.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;
                    }
                }
            }
            message.MinerTransaction.ChainHash = chainHash;
            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)
                });
            }
        }
示例#16
0
 private void OnRelay(IInventory inventory)
 {
     if (!IsFullNode)
     {
         return;
     }
     //if (inventory.InventoryType == InventoryType.TX)
     //{
     //    if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory))
     //        return;
     //}
     EnqueueMessage(MessageCommand.Inv, InvPayload.Create(inventory.InventoryType, inventory.Hash));
 }
示例#17
0
        private void OnInvMessageReceived(InvPayload payload)
        {
            TR.Enter();
            if (payload.Type != InventoryType.TX && payload.Type != InventoryType.Block && payload.Type != InventoryType.Consensus)
            {
                TR.Exit(); return;
            }
            HashSet <UInt256> hashes = new HashSet <UInt256>(payload.Hashes);

            lock (LocalNode.KnownHashes)
            {
                hashes.RemoveWhere(p => LocalNode.KnownHashes.TryGetValue(p, out DateTime time) && time + LocalNode.HashesExpiration >= DateTime.UtcNow);
            }
            if (hashes.Count == 0)
            {
                TR.Exit(); return;
            }
            lock (missions_global)
            {
                lock (missions)
                {
                    if (localNode.GlobalMissionsEnabled)
                    {
                        hashes.RemoveWhere(p => missions_global.TryGetValue(p, out DateTime time) && time + MissionExpiration >= DateTime.UtcNow);
                    }
                    if (hashes.Count > 0)
                    {
                        if (missions.Count == 0)
                        {
                            mission_start = DateTime.Now;
                        }
                        foreach (UInt256 hash in hashes)
                        {
                            if (!missions_global.ContainsKey(hash))
                            {
                                missions_global.Add(hash, DateTime.UtcNow);
                            }
                        }
                        missions.UnionWith(hashes);
                    }
                }
            }
            if (hashes.Count == 0)
            {
                TR.Exit(); return;
            }
            EnqueueMessage("getdata", InvPayload.Create(payload.Type, hashes.ToArray()));
            TR.Exit();
        }
示例#18
0
 private void OnRelay(IInventory inventory)
 {
     if (Version?.Services.HasFlag(VersionServices.AcceptRelay) != true)
     {
         return;
     }
     if (inventory.InventoryType == InventoryType.TX)
     {
         if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory))
         {
             return;
         }
     }
     EnqueueMessage(MessageCommand.Inv, InvPayload.Create(inventory.InventoryType, inventory.Hash));
 }
示例#19
0
 private void OnRelay(IInventory inventory)
 {
     if (Version?.Relay != true)
     {
         return;
     }
     if (inventory.InventoryType == InventoryType.TX)
     {
         if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory))
         {
             return;
         }
     }
     EnqueueMessage("inv", InvPayload.Create(inventory.InventoryType, inventory.Hash));
 }
示例#20
0
        private bool OnBroadcastCommand(string[] args)
        {
            if (!Enum.TryParse(args[1], true, out MessageCommand command))
            {
                Console.WriteLine($"Command \"{args[1]}\" is not supported.");
                return(true);
            }
            ISerializable payload = null;

            switch (command)
            {
            case MessageCommand.Addr:
                payload = AddrPayload.Create(NetworkAddressWithTime.Create(IPAddress.Parse(args[2]), DateTime.UtcNow.ToTimestamp(), new FullNodeCapability(), new ServerCapability(NodeCapabilityType.TcpServer, ushort.Parse(args[3]))));
                break;

            case MessageCommand.Block:
                if (args[2].Length == 64 || args[2].Length == 66)
                {
                    payload = Blockchain.Singleton.GetBlock(UInt256.Parse(args[2]));
                }
                else
                {
                    payload = Blockchain.Singleton.Store.GetBlock(uint.Parse(args[2]));
                }
                break;

            case MessageCommand.GetBlocks:
            case MessageCommand.GetHeaders:
                payload = GetBlocksPayload.Create(UInt256.Parse(args[2]));
                break;

            case MessageCommand.GetData:
            case MessageCommand.Inv:
                payload = InvPayload.Create(Enum.Parse <InventoryType>(args[2], true), args.Skip(3).Select(UInt256.Parse).ToArray());
                break;

            case MessageCommand.Transaction:
                payload = Blockchain.Singleton.GetTransaction(UInt256.Parse(args[2]));
                break;

            default:
                Console.WriteLine($"Command \"{command}\" is not supported.");
                return(true);
            }
            system.LocalNode.Tell(Message.Create(command, payload));
            return(true);
        }
示例#21
0
文件: RemoteNode.cs 项目: ys8090/NEU
 internal bool Relay(IInventory data)
 {
     if (Version?.Relay != true)
     {
         return(false);
     }
     if (data.InventoryType == InventoryType.TX)
     {
         BloomFilter filter = bloom_filter;
         if (filter != null && !TestFilter(filter, (Transaction)data))
         {
             return(false);
         }
     }
     EnqueueMessage("inv", InvPayload.Create(data.InventoryType, data.Hash));
     return(true);
 }
示例#22
0
文件: RemoteNode.cs 项目: ys8090/NEU
        internal void Relay(IEnumerable <Transaction> transactions)
        {
            if (Version?.Relay != true)
            {
                return;
            }
            BloomFilter filter = bloom_filter;

            if (filter != null)
            {
                transactions = transactions.Where(p => TestFilter(filter, p));
            }
            UInt256[] hashes = transactions.Select(p => p.Hash).ToArray();
            if (hashes.Length == 0)
            {
                return;
            }
            EnqueueMessage("inv", InvPayload.Create(InventoryType.TX, hashes));
        }
示例#23
0
        private void OnGetBlocksMessageReceived(Message msg)
        {
            GetBlocksPayload payload = msg.GetPayload <GetBlocksPayload>();

            UInt256 hash = payload.HashStart[0];

            if (hash == payload.HashStop)
            {
                return;
            }
            BlockState state = blockchain.Store.GetBlocks().TryGet(hash);

            if (state == null)
            {
                return;
            }
            List <UInt256> hashes = new List <UInt256>();

            for (uint i = 1; i <= InvPayload.MaxHashesCount; i++)
            {
                uint index = state.TrimmedBlock.Index + i;
                if (index > blockchain.Height)
                {
                    break;
                }
                hash = blockchain.GetBlockHash(index);
                if (hash == null)
                {
                    break;
                }
                if (hash == payload.HashStop)
                {
                    break;
                }
                hashes.Add(hash);
            }
            if (hashes.Count == 0)
            {
                return;
            }
            Context.Parent.Tell(Message.Create(MessageType.Inv, InvPayload.Create(InventoryType.Block, hashes.ToArray())));
            blockchain.Log($"OnGetBlocks, blockIndex:{state.TrimmedBlock.Index}, count:{hashes.Count}, [{remoteNode.Remote.Address}]");
        }
示例#24
0
        private bool OnBroadcastCommand(string[] args)
        {
            string        command = args[1].ToLower();
            ISerializable payload = null;

            switch (command)
            {
            case "addr":
                payload = AddrPayload.Create(NetworkAddressWithTime.Create(new IPEndPoint(IPAddress.Parse(args[2]), ushort.Parse(args[3])), NetworkAddressWithTime.NODE_NETWORK, DateTime.UtcNow.ToTimestamp()));
                break;

            case "block":
                if (args[2].Length == 64 || args[2].Length == 66)
                {
                    payload = Blockchain.Singleton.GetBlock(UInt256.Parse(args[2]));
                }
                else
                {
                    payload = Blockchain.Singleton.Store.GetBlock(uint.Parse(args[2]));
                }
                break;

            case "getblocks":
            case "getheaders":
                payload = GetBlocksPayload.Create(UInt256.Parse(args[2]));
                break;

            case "getdata":
            case "inv":
                payload = InvPayload.Create(Enum.Parse <InventoryType>(args[2], true), args.Skip(3).Select(UInt256.Parse).ToArray());
                break;

            case "tx":
                payload = Blockchain.Singleton.GetTransaction(UInt256.Parse(args[2]));
                break;

            default:
                Console.WriteLine($"Command \"{command}\" is not supported.");
                return(true);
            }
            system.LocalNode.Tell(Message.Create(command, payload));
            return(true);
        }
示例#25
0
 private void OnTimeout(object state)
 {
     lock (context)
     {
         if (timer_height != context.BlockIndex || timer_view != context.ViewNumber)
         {
             return;
         }
         Log($"timeout: height={timer_height} view={timer_view} state={context.State}");
         if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent))
         {
             Log($"send perpare request: height={timer_height} view={timer_view}");
             context.State |= ConsensusState.RequestSent;
             if (!context.State.HasFlag(ConsensusState.SignatureSent))
             {
                 context.Timestamp = Math.Max(DateTime.Now.ToTimestamp(), Blockchain.Default.GetHeader(context.PrevHash).Timestamp + 1);
                 context.Nonce     = GetNonce();
                 List <Transaction> transactions = LocalNode.GetMemoryPool().Where(p => CheckPolicy(p)).ToList();
                 if (transactions.Count >= Settings.Default.MaxTransactionsPerBlock)
                 {
                     transactions = transactions.OrderByDescending(p => p.NetworkFee / p.Size).Take(Settings.Default.MaxTransactionsPerBlock - 1).ToList();
                 }
                 transactions.Insert(0, CreateMinerTransaction(transactions, context.BlockIndex, context.Nonce));
                 context.TransactionHashes           = transactions.Select(p => p.Hash).ToArray();
                 context.Transactions                = transactions.ToDictionary(p => p.Hash);
                 context.NextConsensus               = Blockchain.GetConsensusAddress(Blockchain.Default.GetValidators(transactions).ToArray());
                 context.Signatures[context.MyIndex] = context.MakeHeader().Sign(context.KeyPair);
             }
             InvPayload invPayload = InvPayload.Create(InventoryType.TX, context.TransactionHashes);
             foreach (RemoteNode node in localNode.GetRemoteNodes())
             {
                 node.EnqueueMessage("inv", invPayload);
             }
             SignAndRelay(context.MakePrepareRequest());
             timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (timer_view + 1)), Timeout.InfiniteTimeSpan);
         }
         else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup))
         {
             RequestChangeView();
         }
     }
 }
示例#26
0
 private void OnInvMessageReceived(InvPayload payload)
 {
     if (payload.Type != InventoryType.TX && payload.Type != InventoryType.Block && payload.Type != InventoryType.Consensus)
     {
         return;
     }
     UInt256[] hashes = payload.Hashes.Distinct().ToArray();
     lock (LocalNode.KnownHashes)
     {
         hashes = hashes.Where(p => !LocalNode.KnownHashes.ContainsKey(p) || DateTime.UtcNow - LocalNode.KnownHashes[p] > LocalNode.HashesExpiration).ToArray();
     }
     if (hashes.Length == 0)
     {
         return;
     }
     lock (missions_global)
     {
         lock (missions)
         {
             if (localNode.GlobalMissionsEnabled)
             {
                 hashes = hashes.Where(p => !missions_global.Contains(p)).ToArray();
             }
             if (hashes.Length > 0)
             {
                 if (missions.Count == 0)
                 {
                     mission_start = DateTime.Now;
                 }
                 missions_global.UnionWith(hashes);
                 missions.UnionWith(hashes);
             }
         }
     }
     if (hashes.Length == 0)
     {
         return;
     }
     EnqueueMessage("getdata", InvPayload.Create(payload.Type, hashes));
 }
示例#27
0
        private void OnGetBlocksMessageReceived(GetBlocksPayload payload)
        {
            UInt256 hash = payload.HashStart[0];

            if (hash == payload.HashStop)
            {
                return;
            }
            BlockState state = blockchain.Store.GetBlocks().TryGet(hash);

            if (state == null)
            {
                return;
            }
            List <UInt256> hashes = new List <UInt256>();

            for (uint i = 1; i <= InvPayload.MaxHashesCount; i++)
            {
                uint index = state.TrimmedBlock.Index + i;
                if (index > blockchain.Height)
                {
                    break;
                }
                hash = blockchain.GetBlockHash(index);
                if (hash == null)
                {
                    break;
                }
                hashes.Add(hash);
            }
            if (hashes.Count == 0)
            {
                return;
            }
            Context.Parent.Tell(Message.Create("inv", InvPayload.Create(InventoryType.Block, hashes.ToArray())));
        }
示例#28
0
 private void OnBroadcastInvCommand(InventoryType type, UInt256[] payload)
 {
     OnBroadcastCommand(MessageCommand.Inv, InvPayload.Create(type, payload));
 }
示例#29
0
 internal async Task RelayAsync(Inventory data)
 {
     await SendMessageAsync("inv", InvPayload.Create(data.InventoryType, data.Hash));
 }
示例#30
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)
                });
            }
        }