古典区块链的实现

 主页   资讯   文章   代码   电子书 

对等通信网络

结构设计

接口定义

public interface IListener : IDisposable  
{  
    event EventHandler<IPeer> OnPeerConnected;  
    void Start();  
    string Address { get; }  
}  
public interface IPeer : IDisposable  
{  
    bool IsConnected { get; }  
    string TargetAddress { get; }  
    string BaseAddress { get; }  
    void Send(CommandBase command);  
    CommandBase Receive();  
    void Connect(string connectionString);  
    void Close(object closingMessage = null);  
}  
public interface IPeerFactory : IDisposable  
{  
    IPeer Produce();  
}  

模拟通信实现

为了简化场景,避免涉及更为艰深的网络通信问题,在此以模拟的形式实现网络通信。

public abstract class InMemoryPeerBase : IPeer  
{  
    protected internal InMemoryPeerBase opposite;  
    protected readonly InMemoryConnectionCenter center;  
    protected Queue<CommandBase> receivedData = new Queue<CommandBase>();  

    protected InMemoryPeerBase(InMemoryConnectionCenter center)  
    {  
        this.center = center;  
    }  

    public string TargetAddress { get; protected set; }  
    public string BaseAddress { get; protected set; }  
    public bool IsConnected { get; protected set; }  

    public abstract void Connect(string connectionString);  
    public void Close(object closingMessage = null)  
    public void Send(CommandBase command)  
    public CommandBase Receive()
}  
public void Send(CommandBase command)  
{  
    this.opposite.receivedData.Enqueue(command);  
}  

public CommandBase Receive()  
{  
    if (this.receivedData.TryDequeue(out var ret))  
    {  
        return ret;  
    }  
    return null; 
}  
public void Close(object closingMessage = null)  
{  
    this.IsConnected = false;  
    this.center.RemovePeer(this);  
}  
public class ActiveInMemoryPeer : InMemoryPeerBase  
{  
    public ActiveInMemoryPeer(InMemoryConnectionCenter center, string address) : base(center)  
    {  
        this.BaseAddress = address;  
    }  

    public override void Connect(string connectionString)  
    {  
        this.TargetAddress = connectionString;  
        if (this.center.Connect(connectionString, this))  
        {  
            this.IsConnected = true;  
            this.center.AddPeer(this);  
        }  
        else  
        {  
            this.IsConnected = false;  
        }  
    }
}  
public class PassiveInMemoryPeer : InMemoryPeerBase  
{  
    public PassiveInMemoryPeer(InMemoryConnectionCenter center, ActiveInMemoryPeer peer) : base(center)  
    {  
        this.opposite = peer;  
        this.opposite.opposite = this;  
        this.BaseAddress = peer.TargetAddress;  
        this.TargetAddress = peer.BaseAddress;  
    }  

    public override void Connect(string connectionString)  
    {  
        throw new NotSupportedException();  
    } 
}  
public class InMemoryPeerFactory : IPeerFactory  
{  
    private readonly InMemoryConnectionCenter center;  
    private readonly InMemoryListener server;  

    public InMemoryPeerFactory(InMemoryConnectionCenter center, InMemoryListener server)  
    {  
        this.center = center;  
        this.server = server;  
    }  

    public IPeer Produce()  
    {  
        return new ActiveInMemoryPeer(this.center, this.server.Address);  
    }
}  
public class InMemoryConnectionCenter  
{  
    private int number = 0;  

    private readonly ConcurrentDictionary<string, InMemoryListener> dicServers = new ConcurrentDictionary<string, InMemoryListener>();  
    private readonly ConcurrentDictionary<string, List<InMemoryPeerBase>> dicPeers = new ConcurrentDictionary<string, List<InMemoryPeerBase>>();  

    public NodeOptions NodeOptions { get => new NodeOptions { WellKnownNodes = this.ProduceWellKnownNodes() }; }  
    public string[] ProduceWellKnownNodes() => Enumerable.Range(0, this.number).Select(_ => _.ToString()).ToArray();  

    public (IListener listener, IPeerFactory peerFactory) Produce()  
    internal void AddPeer(InMemoryPeerBase peer)  
    internal void RemovePeer(InMemoryPeerBase peer)  
    internal bool Connect(string baseAddress, ActiveInMemoryPeer peer) 
}  
public (IListener listener, IPeerFactory peerFactory) Produce()  
{  
    var listener = this.ProduceListener();  
    var peerFactory = this.ProducePeerFactory(listener);  
    return (listener, peerFactory);  
}  

private InMemoryListener ProduceListener()  
{  
    var address = this.number.ToString();  
    var server = new InMemoryListener(this, address);  
    this.dicServers[address] = server;  
    this.number++;  
    return server;  
}  

private IPeerFactory ProducePeerFactory(InMemoryListener server)  
{  
    return new InMemoryPeerFactory(this, server);
}  
internal void AddPeer(InMemoryPeerBase peer)  
{  
    var key = peer.TargetAddress;  
    if (this.dicPeers.ContainsKey(key))  
        this.dicPeers[key].Add(peer);  
    else  
        this.dicPeers[key] = new List<InMemoryPeerBase>(new[] { peer });  
}  

internal void RemovePeer(InMemoryPeerBase peer)  
{  
    var key = peer.TargetAddress;  
    if (this.dicPeers.ContainsKey(key))  
        this.dicPeers[key].Remove(peer);
}  
internal bool Connect(string baseAddress, ActiveInMemoryPeer peer)  
{  
    return this.dicServers[baseAddress].Connect(peer);  
}  
public class InMemoryListener : IListener  
{  
    private readonly InMemoryConnectionCenter center;  

    public InMemoryListener(InMemoryConnectionCenter center, string address)  
    {  
        this.center = center;  
        this.Address = address;  
    }  

    public event EventHandler<IPeer> OnPeerConnected;  

    public string Address { get; }  

    public void Start() { }  

    internal bool Connect(ActiveInMemoryPeer peer)  
    {  
        var oppositePeer = new PassiveInMemoryPeer(this.center, peer);  
        this.center.AddPeer(oppositePeer);  
        this.OnPeerConnected?.Invoke(this, oppositePeer);  
        return true;  
    }
}  

通信协议

public abstract class CommandBase  
{  
    public abstract string CommandType { get; }  
    public abstract void OnReceived(Node node, ConnectionNode connectionNode);  
}  
public static class Commands  
{  
    public const string Version = nameof(Version);  
    public const string VersionAcknowledge = nameof(VersionAcknowledge);  
    public const string GetBlocks = nameof(GetBlocks);  
    public const string Inventory = nameof(Inventory);  
    public const string GetData = nameof(GetData);  
    public const string Block = nameof(Block);  
    public const string Transaction = nameof(Transaction);  
}