Example #1
0
        private async Task Peer_OnMessage(BitcoinPeer s, IStreamable msg)
        {
            switch (msg)
            {
            case Addr a:
            {
                foreach (var ip in a.Ips)
                {
                    var ep  = new IPEndPoint(ip.Ip.MapToIPv6(), ip.Port);
                    var epb = ep.ToByteArray();
                    if (!await db.SetContainsAsync("hs:nodes:good-nodes", epb) && !await db.SetContainsAsync("hs:nodes:bad-nodes", epb))
                    {
                        QueueNewNode(ep);
                    }
                }
                break;
            }

            case Ping a:
            {
                var pong = new Pong();
                pong.Nonce = a.Nonce;

                await s.WriteMessage(pong);

                break;
            }

            case bitcoin_lib.P2P.Version a:
            {
                GotVersion = true;

                //send verack and log
                await SetNodeDetails(a);

                var va = new VerAck();
                await s.WriteMessage(va);

                var ga = new GetAddr();
                await s.WriteMessage(ga);

                break;
            }
            }
        }
        private async Task Peer_OnMessage(BitcoinPeer s, IStreamable msg)
        {
            switch (msg)
            {
            case bitcoin_lib.P2P.Version a:
            {
                PeerVersion = a;

                if (Peer.IsInbound)
                {
                    await SendVersion();
                }

                var va = new VerAck();
                await s.WriteMessage(va);

                if (Peer.IsInbound && PeerVersion.HighestVersion >= 70014)
                {
                    //send cmpct (i only want my version, i dont care about another version)
                    //no version 1 msg will be sent if version 2 is supported
                    var nVersion = (Peer.ChainParams.Services & (ulong)Services.NODE_WITNESS) != 0 ? 2ul : 1ul;

                    var cmp = new SendCMPCT();
                    cmp.Version = nVersion;
                    cmp.Enabled = true;

                    await s.WriteMessage(cmp);
                }

                if (BlockChain.Mempool.Count == 0)
                {
                    //ask for mempool
                    var mp = new MemPool();
                    await s.WriteMessage(mp);
                }

                var ph = ((IPEndPoint)Peer.RemoteEndpoint).AsHash();
                if (BlockChain.Peers.ContainsKey(ph))
                {
                    //update peer info
                    BlockChain.Peers[ph].LastSeen    = DateTime.Now;
                    BlockChain.Peers[ph].LastVersion = a;
                }
                else
                {
                    //ask the peer for addr info if this is the first time we seen them
                    var ga = new GetAddr();
                    await s.WriteMessage(ga);
                }
                break;
            }

            case Inv a:
            {
                var gd     = new GetData();
                var to_get = new List <Inventory>();

                var sw = new Stopwatch();
                sw.Start();

                to_get.AddRange(a.Inventory.Where(b => b.Type == InventoryType.MSG_TX && !BlockChain.Mempool.ContainsKey(b.Hash)));
                if ((PeerVersion.Services & (ulong)Services.NODE_WITNESS) == 1)
                {
                    to_get.ForEach(b => b.Type = InventoryType.MSG_WITNESS_TX);
                }
                gd.Inventory = to_get.ToArray();

                if (gd.Inventory.Length > 0)
                {
                    //Console.WriteLine($"Asking for {gd.Count} tnxs, {sw.Elapsed.TotalMilliseconds.ToString("0.00")}ms");
                    await s.WriteMessage(gd);
                }
                break;
            }

            case Tx a:
            {
                if (!BlockChain.Mempool.ContainsKey(a.Hash))
                {
                    BlockChain.Mempool.Add(a.Hash, a);
                }
                break;
            }

            case VerAck a:
            {
                if (Peer.IsInbound)
                {
                    await SendAddr();
                }

                await s.WriteMessage(new Ping());

                break;
            }

            case Addr a:
            {
                foreach (var ip in a.Ips)
                {
                    var ph = new IPEndPoint(ip.Ip, ip.Port).AsHash();
                    if (!BlockChain.Peers.ContainsKey(ph))
                    {
                        BlockChain.Peers.Add(ph, new PeerInfo()
                            {
                                Ip          = Peer.RemoteEndpoint,
                                LastSeen    = DateTime.Now,
                                LastVersion = new bitcoin_lib.P2P.Version()     //add empty version
                            });
                    }
                }
                break;
            }

            case Pong a:
            {
                if (PingTimer.IsRunning)
                {
                    PingTimer.Stop();
                }

                //Console.WriteLine($"[{RemoteEndpoint}]{PeerVersion.UserAgent} ping is: {LastPing.TotalMilliseconds.ToString("0.00")}ms");
                break;
            }

            case Ping a:
            {
                var pong = new Pong();
                pong.Nonce = a.Nonce;

                await s.WriteMessage(pong);

                break;
            }

            case MemPool a:
            {
                var inv = new Inv();
                inv.Inventory = BlockChain.Mempool.Keys.Select(b => new Inventory()
                    {
                        Type = InventoryType.MSG_TX,
                        Hash = b
                    }).ToArray();

                if (inv.Inventory.Length > 0)
                {
                    await s.WriteMessage(inv);
                }
                break;
            }

            case SendCMPCT a:
            {
                if (CMPCTBlockVersion == 0 && a.Enabled && a.Version <= 2)
                {
                    if (Peer.IsInbound)
                    {
                        //lock in cmpct
                        var nVersion = (Peer.ChainParams.Services & (ulong)Services.NODE_WITNESS) != 0 ? 2ul : 1ul;
                        if (a.Version == nVersion)
                        {
                            CMPCTBlockVersion = a.Version;
                            Console.WriteLine($"Locking version {a.Version} cmpct block");
                        }
                    }
                    else
                    {
                        //reply to cmpct negotiation, if the node advertises witness use version 2
                        var nVersion = (PeerVersion.Services & (ulong)Services.NODE_WITNESS) != 0 ? 2ul : 1ul;
                        if (a.Version == nVersion)
                        {
                            CMPCTBlockVersion = a.Version;
                        }
                        else if (nVersion != a.Version && CMPCTBlockVersion == 0)         //if they only sent version 1 & they advertise NODE_WITNESS, use this version
                        {
                            CMPCTBlockVersion = a.Version;
                        }

                        var rsp = new SendCMPCT();
                        rsp.Version = CMPCTBlockVersion;
                        rsp.Enabled = true;

                        Console.WriteLine($"Sending version {rsp.Version} cmpct block");
                        await s.WriteMessage(rsp);
                    }
                    Console.WriteLine($"Peer is asking for version {a.Version} cmpct block");
                }
                break;
            }
            }
        }
Example #3
0
        public async Task UpdateNodeInfo(Node n)
        {
            //Console.WriteLine($"Update node info: {n.IP}");
            try
            {
                //try to connect to the node to get version info and to get its peers
                var ns = new Socket(SocketType.Stream, ProtocolType.Tcp);
                await ns.ConnectAsync(n.IP);

                var p = new BitcoinPeer(ns);
                //Console.WriteLine($"Connected to {n.IP}");
                var ss = new SemaphoreSlim(0, 1);
                var db = Redis.GetDatabase();

                p.OnVersion += async(s, v) =>
                {
                    //send verack and log
                    var ip  = new IPEndPoint(((IPEndPoint)s.RemoteEndpoint).Address.MapToIPv6(), ((IPEndPoint)s.RemoteEndpoint).Port);
                    var ipb = ip.ToByteArray();
                    await db.HashSetAsync($"hs:nodes:detail:{ip.ToString()}", "version", v.ToArray());

                    if (await db.SortedSetAddAsync("hs:nodes:all-nodes", ipb, DateTime.Now.Ticks))
                    {
                        //Console.WriteLine($"Got new node: {ip}");
                        await db.SetRemoveAsync("hs:nodes:new-nodes", ipb);

                        var gloc = GeoIp.City(ip.Address);
                        if (gloc.Location.HasCoordinates)
                        {
                            await db.GeoAddAsync("hs:nodes:geo", new GeoEntry(gloc.Location.Longitude.Value, gloc.Location.Latitude.Value, ipb));
                        }
                    }


                    var va = new VerAck();
                    await s.WriteMessage(va);

                    var ga = new GetAddr();
                    await s.WriteMessage(ga);
                };

                p.OnAddr += async(s, a) =>
                {
                    //Console.WriteLine($"Got {a.IpCount.Value} ips");
                    foreach (var ip in a.Ips)
                    {
                        var ep  = new IPEndPoint(ip.Ip.MapToIPv6(), ip.Port);
                        var epb = ep.ToByteArray();
                        if (await db.SetAddAsync("hs:nodes:new-nodes", epb))
                        {
                            //Console.WriteLine($"Got new node: {ep}");
                        }
                    }

                    s.Stop();

                    ss.Release();

                    //Console.WriteLine($"Disconnected from {n.IP}");
                };

                p.Start();

                Ver.Timestamp = (UInt64)DateTimeOffset.Now.ToUnixTimeSeconds();

                await p.WriteMessage(Ver);

                await ss.WaitAsync(TimeSpan.FromSeconds(5));
            }
            catch (Exception ex)
            {
                //Console.WriteLine(ex);
            }
        }
Example #4
0
        private async Task ReadStream()
        {
            while (!Closing)
            {
                try
                {
                    //try to read a header
                    var hdata = new byte[24];
                    await Stream.ReadAsyncExact(hdata, 0, hdata.Length);

                    var h = new MessageHeader();
                    h.ReadFromPayload(hdata, 0);
                    if (h != null)
                    {
                        //read the payload
                        var pl = new byte[h.PayloadSize];
                        await Stream.ReadAsyncExact(pl, 0, pl.Length);

                        bool checksumOk = false;

                        //verify hash
                        using (var sha = SHA256.Create())
                        {
                            var h1 = sha.ComputeHash(pl);
                            var h2 = sha.ComputeHash(h1);

                            checksumOk = h2[0] == h.Checksum[0] && h2[1] == h.Checksum[1] && h2[2] == h.Checksum[2] && h2[3] == h.Checksum[3];
                        }

                        if (checksumOk)
                        {
                            switch (h.Command)
                            {
                            case "addr\0\0\0\0\0\0\0\0":
                            {
                                if (OnAddr != null)
                                {
                                    var a = new Addr();
                                    a.ReadFromPayload(pl, 0);

                                    await OnAddr?.Invoke(this, a);
                                }
                                break;
                            }

                            case "alert\0\0\0\0\0\0\0":
                            {
                                if (OnAlert != null)
                                {
                                    var a = new Alert();
                                    a.ReadFromPayload(pl, 0);

                                    await OnAlert?.Invoke(this, a);
                                }
                                break;
                            }

                            case "feefilter\0\0\0":
                            {
                                if (OnFeeFilter != null)
                                {
                                    var f = new FeeFilter();
                                    f.ReadFromPayload(pl, 0);

                                    await OnFeeFilter?.Invoke(this, f);
                                }
                                break;
                            }

                            case "filteradd\0\0\0":
                            {
                                if (OnFilterAdd != null)
                                {
                                    var f = new FilterAdd();
                                    f.ReadFromPayload(pl, 0);

                                    await OnFilterAdd?.Invoke(this, f);
                                }
                                break;
                            }

                            case "filterclear\0":
                            {
                                if (OnFilterClear != null)
                                {
                                    var f = new FilterClear();
                                    f.ReadFromPayload(pl, 0);

                                    await OnFilterClear?.Invoke(this, f);
                                }
                                break;
                            }

                            case "filterload\0\0":
                            {
                                if (OnFilterLoad != null)
                                {
                                    var f = new FilterLoad();
                                    f.ReadFromPayload(pl, 0);

                                    await OnFilterLoad?.Invoke(this, f);
                                }
                                break;
                            }

                            case "getaddr\0\0\0\0\0":
                            {
                                if (OnGetAddr != null)
                                {
                                    var ga = new GetAddr();
                                    ga.ReadFromPayload(pl, 0);

                                    await OnGetAddr?.Invoke(this, ga);
                                }
                                break;
                            }

                            case "getblocks\0\0\0":
                            {
                                if (OnGetBlocks != null)
                                {
                                    var gb = new GetBlocks();
                                    gb.ReadFromPayload(pl, 0);

                                    await OnGetBlocks?.Invoke(this, gb);
                                }
                                break;
                            }

                            case "getdata\0\0\0\0\0":
                            {
                                if (OnGetData != null)
                                {
                                    var gd = new GetData();
                                    gd.ReadFromPayload(pl, 0);

                                    await OnGetData?.Invoke(this, gd);
                                }
                                break;
                            }

                            case "getheaders\0\0":
                            {
                                if (OnGetHeaders != null)
                                {
                                    var gh = new GetHeaders();
                                    gh.ReadFromPayload(pl, 0);

                                    await OnGetHeaders?.Invoke(this, gh);
                                }
                                break;
                            }

                            case "headers\0\0\0\0\0":
                            {
                                if (OnHeaders != null)
                                {
                                    var hd = new Headers();
                                    hd.ReadFromPayload(pl, 0);

                                    await OnHeaders?.Invoke(this, hd);
                                }
                                break;
                            }

                            case "inv\0\0\0\0\0\0\0\0\0":
                            {
                                if (OnInv != null)
                                {
                                    var iv = new Inv();
                                    iv.ReadFromPayload(pl, 0);

                                    await OnInv?.Invoke(this, iv);
                                }
                                break;
                            }

                            case "mempool\0\0\0\0\0":
                            {
                                if (OnMemPool != null)
                                {
                                    var mp = new MemPool();
                                    mp.ReadFromPayload(pl, 0);

                                    await OnMemPool?.Invoke(this, mp);
                                }
                                break;
                            }

                            case "notfound\0\0\0\0":
                            {
                                if (OnNotFound != null)
                                {
                                    var nf = new NotFound();
                                    nf.ReadFromPayload(pl, 0);

                                    await OnNotFound?.Invoke(this, nf);
                                }
                                break;
                            }

                            case "ping\0\0\0\0\0\0\0\0":
                            {
                                if (OnPing != null)
                                {
                                    var ping = new Ping();
                                    ping.ReadFromPayload(pl, 0);

                                    await OnPing?.Invoke(this, ping);
                                }
                                break;
                            }

                            case "pong\0\0\0\0\0\0\0\0":
                            {
                                if (OnPong != null)
                                {
                                    var pong = new Pong();
                                    pong.ReadFromPayload(pl, 0);

                                    await OnPong?.Invoke(this, pong);
                                }
                                break;
                            }

                            case "reject\0\0\0\0\0\0":
                            {
                                if (OnReject != null)
                                {
                                    var re = new Reject();
                                    re.ReadFromPayload(pl, 0);

                                    await OnReject?.Invoke(this, re);
                                }
                                break;
                            }

                            case "sendheaders\0":
                            {
                                if (OnSendHeaders != null)
                                {
                                    var sh = new SendHeaders();
                                    sh.ReadFromPayload(pl, 0);

                                    await OnSendHeaders?.Invoke(this, sh);
                                }
                                break;
                            }

                            case "verack\0\0\0\0\0\0":
                            {
                                if (OnVerAck != null)
                                {
                                    var va = new VerAck();
                                    va.ReadFromPayload(pl, 0);

                                    await OnVerAck.Invoke(this, va);
                                }
                                break;
                            }

                            case "version\0\0\0\0\0":
                            {
                                if (OnVersion != null)
                                {
                                    var v = new bitcoin_lib.P2P.Version("");
                                    v.ReadFromPayload(pl, 0);

                                    await OnVersion?.Invoke(this, v);
                                }
                                break;
                            }

                            default:
                            {
                                //Console.WriteLine($"Got cmd: {h.Command}");
                                break;
                            }
                            }
                        }
                        else
                        {
                            Closing = true;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Closing = true;
                }
            }
        }
Example #5
0
 private Task Peer_OnGetAddr(BitcoinPeer s, GetAddr a)
 {
     throw new NotImplementedException();
 }
Example #6
0
        private static async Task RunNode()
        {
            try
            {
                BlockChain.Init();

                var cp_btc = new ChainParams();

                Node        = new BitcoinNode <BitcoinNodePeer>(cp_btc, new IPEndPoint(IPAddress.Any, 8336));
                Node.OnLog += Node_OnLog;

                Node.Start();

                //var ct = node.AddPeer(new IPEndPoint(IPAddress.Parse("192.168.254.6"), 8333));
                //var ct2 = node.AddPeer(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8333));

                //if no peers, add seeds
                if (BlockChain.Peers.Count == 0)
                {
                    Console.WriteLine("No peers found, adding seed nodes..");
                    foreach (var seed in DNSSeeds)
                    {
                        try
                        {
                            var ips = await Dns.GetHostAddressesAsync(seed);

                            foreach (var ip in ips)
                            {
                                var ep = new IPEndPoint(ip, 8333);
                                BlockChain.Peers.Add(ep.AsHash(), new PeerInfo()
                                {
                                    Ip          = ep,
                                    LastSeen    = DateTime.Now,
                                    LastVersion = new bitcoin_lib.P2P.Version()
                                });
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"No ips found for seed: {seed} ({ex.Message})");
                        }
                    }
                }

                //connect to last 8 peers
                await TryAddLastPeers();

                bool exit = false;
                Console.CancelKeyPress += (s, e) =>
                {
                    Console.WriteLine($"Shutting down..");
                    exit = true;

                    //doesnt work in .net core it seems..
                    //https://github.com/dotnet/coreclr/issues/8565
                };

                while (!exit)
                {
                    //ping the peers every 60s
                    if ((DateTime.Now - LastPingSent).TotalSeconds >= 60)
                    {
                        //disconnect a high ping node
                        BitcoinNodePeer hpn = Node.EnumeratePeers().Where(a => a.LastPing != TimeSpan.Zero).OrderByDescending(a => a.LastPing.TotalMilliseconds).FirstOrDefault();
                        if (hpn != default)
                        {
                            hpn.Disconnect();
                        }

                        var pt = new List <Task>();
                        foreach (var n in Node.EnumeratePeers())
                        {
                            pt.Add(n.StartPing());
                        }
                        await Task.WhenAll(pt);

                        LastPingSent = DateTime.Now;
                    }

                    //try to get 8 peers
                    if (Node.EnumeratePeers().Count() < 8)
                    {
                        //ask for more peers if we dont have enough
                        if (BlockChain.Peers.Count < 100)
                        {
                            Console.WriteLine($"Not enough known peers, asking for more..");
                            foreach (var n in Node.EnumeratePeers())
                            {
                                var addr = new GetAddr();
                                await n.WriteMessage(addr);
                            }

                            //wait 2s for nodes to reply
                            await Task.Delay(2000);
                        }

                        await TryAddLastPeers();
                    }

                    await Task.Delay(100);
                }

                await ShutdownNode();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }