diff --git a/AntShares.sln b/AntShares.sln index a3f97a75ca..a8c7f46e1e 100644 --- a/AntShares.sln +++ b/AntShares.sln @@ -7,8 +7,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AntSharesCore", "AntSharesC EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AntSharesUI", "AntSharesUI\AntSharesUI.csproj", "{CFC243F0-F4E3-4754-8E21-8BA17E1C1788}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Miner", "Miner\Miner.csproj", "{58870D2E-9DAE-41EF-9766-17C39238ED0F}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AntSharesDaemon", "AntSharesDaemon\AntSharesDaemon.csproj", "{3E7DD63A-6AD5-41F1-837D-42C11694246C}" EndProject Global @@ -25,10 +23,6 @@ Global {CFC243F0-F4E3-4754-8E21-8BA17E1C1788}.Debug|Any CPU.Build.0 = Debug|Any CPU {CFC243F0-F4E3-4754-8E21-8BA17E1C1788}.Release|Any CPU.ActiveCfg = Release|Any CPU {CFC243F0-F4E3-4754-8E21-8BA17E1C1788}.Release|Any CPU.Build.0 = Release|Any CPU - {58870D2E-9DAE-41EF-9766-17C39238ED0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {58870D2E-9DAE-41EF-9766-17C39238ED0F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {58870D2E-9DAE-41EF-9766-17C39238ED0F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {58870D2E-9DAE-41EF-9766-17C39238ED0F}.Release|Any CPU.Build.0 = Release|Any CPU {3E7DD63A-6AD5-41F1-837D-42C11694246C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3E7DD63A-6AD5-41F1-837D-42C11694246C}.Debug|Any CPU.Build.0 = Debug|Any CPU {3E7DD63A-6AD5-41F1-837D-42C11694246C}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/AntSharesCore/AntSharesCore.csproj b/AntSharesCore/AntSharesCore.csproj index be0474eac2..a798bc91d8 100644 --- a/AntSharesCore/AntSharesCore.csproj +++ b/AntSharesCore/AntSharesCore.csproj @@ -130,6 +130,14 @@ + + + + + + + + diff --git a/Miner/Miner/Consensus/ChangeView.cs b/AntSharesCore/Consensus/ChangeView.cs similarity index 90% rename from Miner/Miner/Consensus/ChangeView.cs rename to AntSharesCore/Consensus/ChangeView.cs index 8d254bb963..2916c312d0 100644 --- a/Miner/Miner/Consensus/ChangeView.cs +++ b/AntSharesCore/Consensus/ChangeView.cs @@ -1,28 +1,28 @@ -using System; -using System.IO; - -namespace AntShares.Miner.Consensus -{ - internal class ChangeView : ConsensusMessage - { - public byte NewViewNumber; - - public ChangeView() - : base(ConsensusMessageType.ChangeView) - { - } - - public override void Deserialize(BinaryReader reader) - { - base.Deserialize(reader); - NewViewNumber = reader.ReadByte(); - if (NewViewNumber == 0) throw new FormatException(); - } - - public override void Serialize(BinaryWriter writer) - { - base.Serialize(writer); - writer.Write(NewViewNumber); - } - } -} +using System; +using System.IO; + +namespace AntShares.Consensus +{ + internal class ChangeView : ConsensusMessage + { + public byte NewViewNumber; + + public ChangeView() + : base(ConsensusMessageType.ChangeView) + { + } + + public override void Deserialize(BinaryReader reader) + { + base.Deserialize(reader); + NewViewNumber = reader.ReadByte(); + if (NewViewNumber == 0) throw new FormatException(); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(NewViewNumber); + } + } +} diff --git a/Miner/Miner/Consensus/ConsensusContext.cs b/AntSharesCore/Consensus/ConsensusContext.cs similarity index 96% rename from Miner/Miner/Consensus/ConsensusContext.cs rename to AntSharesCore/Consensus/ConsensusContext.cs index 00f192e22f..3bea02ea59 100644 --- a/Miner/Miner/Consensus/ConsensusContext.cs +++ b/AntSharesCore/Consensus/ConsensusContext.cs @@ -1,132 +1,132 @@ -using AntShares.Core; -using AntShares.Cryptography; -using AntShares.Cryptography.ECC; -using AntShares.IO; -using AntShares.Network.Payloads; -using AntShares.Wallets; -using System.Collections.Generic; -using System.Linq; - -namespace AntShares.Miner.Consensus -{ - internal class ConsensusContext - { - public const uint Version = 0; - public ConsensusState State; - public UInt256 PrevHash; - public uint Height; - public byte ViewNumber; - public ECPoint[] Miners; - public int MinerIndex; - public uint PrimaryIndex; - public uint Timestamp; - public ulong Nonce; - public UInt160 NextMiner; - public UInt256[] TransactionHashes; - public Dictionary Transactions; - public byte[][] Signatures; - public byte[] ExpectedView; - - public int M => Miners.Length - (Miners.Length - 1) / 3; - - public void ChangeView(byte view_number) - { - int p = ((int)Height - view_number) % Miners.Length; - State &= ConsensusState.SignatureSent; - ViewNumber = view_number; - PrimaryIndex = p >= 0 ? (uint)p : (uint)(p + Miners.Length); - if (State == ConsensusState.Initial) - { - TransactionHashes = null; - Signatures = new byte[Miners.Length][]; - } - _header = null; - } - - public ConsensusPayload MakeChangeView() - { - return MakePayload(new ChangeView - { - NewViewNumber = ExpectedView[MinerIndex] - }); - } - - private Block _header = null; - public Block MakeHeader() - { - if (TransactionHashes == null) return null; - if (_header == null) - { - _header = new Block - { - Version = Version, - PrevBlock = PrevHash, - MerkleRoot = MerkleTree.ComputeRoot(TransactionHashes), - Timestamp = Timestamp, - Height = Height, - Nonce = Nonce, - NextMiner = NextMiner, - Transactions = new Transaction[0] - }; - } - return _header; - } - - private ConsensusPayload MakePayload(ConsensusMessage message) - { - message.ViewNumber = ViewNumber; - return new ConsensusPayload - { - Version = Version, - PrevHash = PrevHash, - Height = Height, - MinerIndex = (ushort)MinerIndex, - Timestamp = Timestamp, - Data = message.ToArray() - }; - } - - public ConsensusPayload MakePerpareRequest() - { - return MakePayload(new PerpareRequest - { - Nonce = Nonce, - NextMiner = NextMiner, - TransactionHashes = TransactionHashes, - MinerTransaction = (MinerTransaction)Transactions[TransactionHashes[0]], - Signature = Signatures[MinerIndex] - }); - } - - public ConsensusPayload MakePerpareResponse(byte[] signature) - { - return MakePayload(new PerpareResponse - { - Signature = signature - }); - } - - public void Reset(Wallet wallet) - { - State = ConsensusState.Initial; - PrevHash = Blockchain.Default.CurrentBlockHash; - Height = Blockchain.Default.Height + 1; - ViewNumber = 0; - Miners = Blockchain.Default.GetMiners(); - MinerIndex = -1; - PrimaryIndex = Height % (uint)Miners.Length; - TransactionHashes = null; - Signatures = new byte[Miners.Length][]; - ExpectedView = new byte[Miners.Length]; - for (int i = 0; i < Miners.Length; i++) - { - if (wallet.ContainsAccount(Miners[i])) - { - MinerIndex = i; - break; - } - } - _header = null; - } - } -} +using AntShares.Core; +using AntShares.Cryptography; +using AntShares.Cryptography.ECC; +using AntShares.IO; +using AntShares.Network.Payloads; +using AntShares.Wallets; +using System.Collections.Generic; +using System.Linq; + +namespace AntShares.Consensus +{ + internal class ConsensusContext + { + public const uint Version = 0; + public ConsensusState State; + public UInt256 PrevHash; + public uint Height; + public byte ViewNumber; + public ECPoint[] Miners; + public int MinerIndex; + public uint PrimaryIndex; + public uint Timestamp; + public ulong Nonce; + public UInt160 NextMiner; + public UInt256[] TransactionHashes; + public Dictionary Transactions; + public byte[][] Signatures; + public byte[] ExpectedView; + + public int M => Miners.Length - (Miners.Length - 1) / 3; + + public void ChangeView(byte view_number) + { + int p = ((int)Height - view_number) % Miners.Length; + State &= ConsensusState.SignatureSent; + ViewNumber = view_number; + PrimaryIndex = p >= 0 ? (uint)p : (uint)(p + Miners.Length); + if (State == ConsensusState.Initial) + { + TransactionHashes = null; + Signatures = new byte[Miners.Length][]; + } + _header = null; + } + + public ConsensusPayload MakeChangeView() + { + return MakePayload(new ChangeView + { + NewViewNumber = ExpectedView[MinerIndex] + }); + } + + private Block _header = null; + public Block MakeHeader() + { + if (TransactionHashes == null) return null; + if (_header == null) + { + _header = new Block + { + Version = Version, + PrevBlock = PrevHash, + MerkleRoot = MerkleTree.ComputeRoot(TransactionHashes), + Timestamp = Timestamp, + Height = Height, + Nonce = Nonce, + NextMiner = NextMiner, + Transactions = new Transaction[0] + }; + } + return _header; + } + + private ConsensusPayload MakePayload(ConsensusMessage message) + { + message.ViewNumber = ViewNumber; + return new ConsensusPayload + { + Version = Version, + PrevHash = PrevHash, + Height = Height, + MinerIndex = (ushort)MinerIndex, + Timestamp = Timestamp, + Data = message.ToArray() + }; + } + + public ConsensusPayload MakePerpareRequest() + { + return MakePayload(new PerpareRequest + { + Nonce = Nonce, + NextMiner = NextMiner, + TransactionHashes = TransactionHashes, + MinerTransaction = (MinerTransaction)Transactions[TransactionHashes[0]], + Signature = Signatures[MinerIndex] + }); + } + + public ConsensusPayload MakePerpareResponse(byte[] signature) + { + return MakePayload(new PerpareResponse + { + Signature = signature + }); + } + + public void Reset(Wallet wallet) + { + State = ConsensusState.Initial; + PrevHash = Blockchain.Default.CurrentBlockHash; + Height = Blockchain.Default.Height + 1; + ViewNumber = 0; + Miners = Blockchain.Default.GetMiners(); + MinerIndex = -1; + PrimaryIndex = Height % (uint)Miners.Length; + TransactionHashes = null; + Signatures = new byte[Miners.Length][]; + ExpectedView = new byte[Miners.Length]; + for (int i = 0; i < Miners.Length; i++) + { + if (wallet.ContainsAccount(Miners[i])) + { + MinerIndex = i; + break; + } + } + _header = null; + } + } +} diff --git a/Miner/Miner/Consensus/ConsensusMessage.cs b/AntSharesCore/Consensus/ConsensusMessage.cs similarity index 94% rename from Miner/Miner/Consensus/ConsensusMessage.cs rename to AntSharesCore/Consensus/ConsensusMessage.cs index 9cec8bdc6f..f377baa459 100644 --- a/Miner/Miner/Consensus/ConsensusMessage.cs +++ b/AntSharesCore/Consensus/ConsensusMessage.cs @@ -1,43 +1,43 @@ -using AntShares.IO; -using System; -using System.IO; - -namespace AntShares.Miner.Consensus -{ - internal abstract class ConsensusMessage : ISerializable - { - public readonly ConsensusMessageType Type; - public byte ViewNumber; - - protected ConsensusMessage(ConsensusMessageType type) - { - this.Type = type; - } - - public virtual void Deserialize(BinaryReader reader) - { - if (Type != (ConsensusMessageType)reader.ReadByte()) - throw new FormatException(); - ViewNumber = reader.ReadByte(); - } - - public static ConsensusMessage DeserializeFrom(byte[] data) - { - ConsensusMessageType type = (ConsensusMessageType)data[0]; - string typeName = $"{typeof(ConsensusMessage).Namespace}.{type}"; - ConsensusMessage message = typeof(ConsensusMessage).Assembly.CreateInstance(typeName) as ConsensusMessage; - using (MemoryStream ms = new MemoryStream(data, false)) - using (BinaryReader r = new BinaryReader(ms)) - { - message.Deserialize(r); - } - return message; - } - - public virtual void Serialize(BinaryWriter writer) - { - writer.Write((byte)Type); - writer.Write(ViewNumber); - } - } -} +using AntShares.IO; +using System; +using System.IO; + +namespace AntShares.Consensus +{ + internal abstract class ConsensusMessage : ISerializable + { + public readonly ConsensusMessageType Type; + public byte ViewNumber; + + protected ConsensusMessage(ConsensusMessageType type) + { + this.Type = type; + } + + public virtual void Deserialize(BinaryReader reader) + { + if (Type != (ConsensusMessageType)reader.ReadByte()) + throw new FormatException(); + ViewNumber = reader.ReadByte(); + } + + public static ConsensusMessage DeserializeFrom(byte[] data) + { + ConsensusMessageType type = (ConsensusMessageType)data[0]; + string typeName = $"{typeof(ConsensusMessage).Namespace}.{type}"; + ConsensusMessage message = typeof(ConsensusMessage).Assembly.CreateInstance(typeName) as ConsensusMessage; + using (MemoryStream ms = new MemoryStream(data, false)) + using (BinaryReader r = new BinaryReader(ms)) + { + message.Deserialize(r); + } + return message; + } + + public virtual void Serialize(BinaryWriter writer) + { + writer.Write((byte)Type); + writer.Write(ViewNumber); + } + } +} diff --git a/Miner/Miner/Consensus/ConsensusMessageType.cs b/AntSharesCore/Consensus/ConsensusMessageType.cs similarity index 76% rename from Miner/Miner/Consensus/ConsensusMessageType.cs rename to AntSharesCore/Consensus/ConsensusMessageType.cs index dbb988503b..91b60a249a 100644 --- a/Miner/Miner/Consensus/ConsensusMessageType.cs +++ b/AntSharesCore/Consensus/ConsensusMessageType.cs @@ -1,9 +1,9 @@ -namespace AntShares.Miner.Consensus -{ - internal enum ConsensusMessageType : byte - { - ChangeView = 0x00, - PerpareRequest = 0x20, - PerpareResponse = 0x21, - } -} +namespace AntShares.Consensus +{ + internal enum ConsensusMessageType : byte + { + ChangeView = 0x00, + PerpareRequest = 0x20, + PerpareResponse = 0x21, + } +} diff --git a/Miner/Miner/MinerService.cs b/AntSharesCore/Consensus/ConsensusService.cs similarity index 66% rename from Miner/Miner/MinerService.cs rename to AntSharesCore/Consensus/ConsensusService.cs index 053c717373..aee4c5c570 100644 --- a/Miner/Miner/MinerService.cs +++ b/AntSharesCore/Consensus/ConsensusService.cs @@ -1,448 +1,346 @@ -using AntShares.Core; -using AntShares.Core.Scripts; -using AntShares.Implementations.Wallets.EntityFramework; -using AntShares.Miner.Consensus; -using AntShares.Network; -using AntShares.Network.Payloads; -using AntShares.Shell; -using AntShares.Wallets; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security; -using System.Threading; - -namespace AntShares.Miner -{ - internal class MinerService : MainService - { - private ConsensusContext context = new ConsensusContext(); - private UserWallet wallet; - private Timer timer; - private uint timer_height; - private byte timer_view; - private DateTime block_received_time; - - private bool AddTransaction(Transaction tx) - { - Program.Log($"{nameof(AddTransaction)} hash:{tx.Hash}"); - if (context.Transactions.SelectMany(p => p.Value.GetAllInputs()).Intersect(tx.GetAllInputs()).Count() > 0 || - Blockchain.Default.ContainsTransaction(tx.Hash) || - !tx.Verify()) - { - Program.Log($"failed hash:{tx.Hash}"); - RequestChangeView(); - return false; - } - context.Transactions[tx.Hash] = tx; - if (context.TransactionHashes.Length == context.Transactions.Count) - { - if (Blockchain.GetMinerAddress(Blockchain.Default.GetMiners(context.Transactions.Values).ToArray()).Equals(context.NextMiner)) - { - Program.Log($"SendPerpareResponse"); - context.State |= ConsensusState.SignatureSent; - context.Signatures[context.MinerIndex] = context.MakeHeader().Sign(wallet.GetAccount(context.Miners[context.MinerIndex])); - SignAndRelay(context.MakePerpareResponse(context.Signatures[context.MinerIndex])); - CheckSignatures(); - } - else - { - RequestChangeView(); - return false; - } - } - return true; - } - - private void Blockchain_PersistCompleted(object sender, Block block) - { - Program.Log($"{nameof(Blockchain_PersistCompleted)} hash:{block.Hash}"); - block_received_time = DateTime.Now; - InitializeConsensus(0); - } - - private void CheckExpectedView(byte view_number) - { - if (context.ViewNumber == view_number) return; - if (context.ExpectedView.Count(p => p == view_number) >= context.M) - { - InitializeConsensus(view_number); - } - } - - private void CheckSignatures() - { - if (context.Signatures.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p))) - { - Program.Log($"{nameof(CheckSignatures)} {context.Signatures.Count(p => p != null)}/{context.M}"); - Contract contract = Contract.CreateMultiSigContract(context.Miners[context.MinerIndex].EncodePoint(true).ToScriptHash(), context.M, context.Miners); - Block block = context.MakeHeader(); - SignatureContext sc = new SignatureContext(block); - for (int i = 0; i < context.Miners.Length; i++) - if (context.Signatures[i] != null) - sc.Add(contract, context.Miners[i], context.Signatures[i]); - sc.Signable.Scripts = sc.GetScripts(); - block.Transactions = context.TransactionHashes.Select(p => context.Transactions[p]).ToArray(); - Program.Log($"RelayBlock hash:{block.Hash}"); - if (!LocalNode.Relay(block)) - Program.Log($"failed hash:{block.Hash}"); - context.State |= ConsensusState.BlockSent; - } - } - - private MinerTransaction CreateMinerTransaction(IEnumerable transactions, uint height, ulong nonce) - { - Fixed8 amount_netfee = Block.CalculateNetFee(transactions); - TransactionOutput[] outputs = amount_netfee == Fixed8.Zero ? new TransactionOutput[0] : new[] { new TransactionOutput - { - AssetId = Blockchain.AntCoin.Hash, - Value = amount_netfee, - ScriptHash = wallet.GetContracts().First().ScriptHash - } }; - return new MinerTransaction - { - Nonce = (uint)(nonce % (uint.MaxValue + 1ul)), - Attributes = new TransactionAttribute[0], - Inputs = new TransactionInput[0], - Outputs = outputs, - Scripts = new Script[0] - }; - } - - private static ulong GetNonce() - { - byte[] nonce = new byte[sizeof(ulong)]; - Random rand = new Random(); - rand.NextBytes(nonce); - return BitConverter.ToUInt64(nonce, 0); - } - - private void InitializeConsensus(byte view_number) - { - lock (context) - { - if (view_number == 0) - context.Reset(wallet); - else - context.ChangeView(view_number); - if (context.MinerIndex < 0) return; - Program.Log($"{nameof(InitializeConsensus)} h:{context.Height} v:{view_number} i:{context.MinerIndex} s:{(context.MinerIndex == context.PrimaryIndex ? ConsensusState.Primary : ConsensusState.Backup)}"); - if (context.MinerIndex == context.PrimaryIndex) - { - context.State |= ConsensusState.Primary; - timer_height = context.Height; - 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.Height; - timer_view = view_number; - timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (view_number + 1)), Timeout.InfiniteTimeSpan); - } - } - } - - private void LocalNode_NewInventory(object sender, IInventory 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); - } - } - } - - private void OnChangeViewReceived(ConsensusPayload payload, ChangeView message) - { - Program.Log($"{nameof(OnChangeViewReceived)} h:{payload.Height} v:{message.ViewNumber} i:{payload.MinerIndex} nv:{message.NewViewNumber}"); - if (message.NewViewNumber <= context.ExpectedView[payload.MinerIndex]) - return; - context.ExpectedView[payload.MinerIndex] = message.NewViewNumber; - CheckExpectedView(message.NewViewNumber); - } - - protected override bool OnCommand(string[] args) - { - switch (args[0].ToLower()) - { - case "create": - return OnCreateCommand(args); - case "list": - return OnListCommand(args); - case "open": - return OnOpenCommand(args); - default: - return base.OnCommand(args); - } - } - - private bool OnCreateCommand(string[] args) - { - switch (args[1].ToLower()) - { - case "wallet": - return OnCreateWalletCommand(args); - default: - return base.OnCommand(args); - } - } - - private bool OnCreateWalletCommand(string[] args) - { - if (args.Length < 3) - { - Console.WriteLine("error"); - return true; - } - using (SecureString password = ReadSecureString("password")) - using (SecureString password2 = ReadSecureString("password")) - { - if (!password.CompareTo(password2)) - { - Console.WriteLine("error"); - return true; - } - wallet = UserWallet.Create(args[2], password); - foreach (Account account in wallet.GetAccounts()) - { - Console.WriteLine(account.PublicKey.EncodePoint(true).ToHexString()); - } - } - return true; - } - - private bool OnListCommand(string[] args) - { - switch (args[1].ToLower()) - { - case "account": - return OnListAccountCommand(args); - case "address": - return OnListAddressCommand(args); - default: - return base.OnCommand(args); - } - } - - private bool OnListAccountCommand(string[] args) - { - if (wallet == null) return true; - foreach (Account account in wallet.GetAccounts()) - { - Console.WriteLine(account.PublicKey); - } - return true; - } - - private bool OnListAddressCommand(string[] args) - { - if (wallet == null) return true; - foreach (Contract contract in wallet.GetContracts()) - { - Console.WriteLine($"{contract.Address}\t{contract.GetType()}"); - } - return true; - } - - private bool OnOpenCommand(string[] args) - { - switch (args[1].ToLower()) - { - case "wallet": - return OnOpenWalletCommand(args); - default: - return base.OnCommand(args); - } - } - - //TODO: 目前没有想到其它安全的方法来保存密码 - //所以只能暂时手动输入,但如此一来就不能以服务的方式启动了 - //未来再想想其它办法,比如采用智能卡之类的 - private bool OnOpenWalletCommand(string[] args) - { - if (args.Length < 3) - { - Console.WriteLine("error"); - return true; - } - using (SecureString password = ReadSecureString("password")) - { - if (password.Length == 0) - { - Console.WriteLine("cancelled"); - return true; - } - try - { - wallet = UserWallet.Open(args[2], password); - } - catch - { - Console.WriteLine($"failed to open file \"{args[2]}\""); - return true; - } - } - StartMine(); - return true; - } - - private void OnPerpareRequestReceived(ConsensusPayload payload, PerpareRequest message) - { - Program.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()) - { - Program.Log($"Timestamp incorrect:{payload.Timestamp}"); - return; - } - context.State |= ConsensusState.RequestReceived; - context.Timestamp = payload.Timestamp; - context.Nonce = message.Nonce; - context.NextMiner = message.NextMiner; - context.TransactionHashes = message.TransactionHashes; - context.Transactions = new Dictionary(); - if (!context.MakeHeader().VerifySignature(context.Miners[payload.MinerIndex], message.Signature)) return; - context.Signatures = new byte[context.Miners.Length][]; - context.Signatures[payload.MinerIndex] = message.Signature; - if (!AddTransaction(message.MinerTransaction)) return; - Dictionary mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash); - foreach (UInt256 hash in context.TransactionHashes.Skip(1)) - if (mempool.ContainsKey(hash)) - if (!AddTransaction(mempool[hash])) - return; - LocalNode.AllowHashes(context.TransactionHashes.Except(context.Transactions.Keys)); - if (context.Transactions.Count < context.TransactionHashes.Length) - LocalNode.SynchronizeMemoryPool(); - } - - private void OnPerpareResponseReceived(ConsensusPayload payload, PerpareResponse message) - { - Program.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(); - } - - protected internal override void OnStop() - { - Program.Log($"{nameof(OnStop)}"); - if (timer != null) timer.Dispose(); - Blockchain.PersistCompleted -= Blockchain_PersistCompleted; - LocalNode.NewInventory -= LocalNode_NewInventory; - base.OnStop(); - } - - private void OnTimeout(object state) - { - Program.Log($"{nameof(OnTimeout)} h:{timer_height} v:{timer_view} state:{context.State}"); - lock (context) - { - if (timer_height != context.Height || timer_view != context.ViewNumber) - { - Program.Log($"ignored"); - return; - } - if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent)) - { - Program.Log($"SendPerpareRequest h:{timer_height} v:{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 transactions = LocalNode.GetMemoryPool().ToList(); - transactions.Insert(0, CreateMinerTransaction(transactions, context.Height, context.Nonce)); - context.TransactionHashes = transactions.Select(p => p.Hash).ToArray(); - context.Transactions = transactions.ToDictionary(p => p.Hash); - context.NextMiner = Blockchain.GetMinerAddress(Blockchain.Default.GetMiners(transactions).ToArray()); - context.Signatures[context.MinerIndex] = context.MakeHeader().Sign(wallet.GetAccount(context.Miners[context.MinerIndex])); - } - SignAndRelay(context.MakePerpareRequest()); - 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(); - } - } - } - - private void RequestChangeView() - { - context.ExpectedView[context.MinerIndex]++; - Program.Log($"{nameof(RequestChangeView)} h:{context.Height} v:{context.ViewNumber} nv:{context.ExpectedView[context.MinerIndex]} state:{context.State}"); - timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (context.ExpectedView[context.MinerIndex] + 1)), Timeout.InfiniteTimeSpan); - SignAndRelay(context.MakeChangeView()); - CheckExpectedView(context.ExpectedView[context.MinerIndex]); - } - - private void SignAndRelay(ConsensusPayload payload) - { - SignatureContext sc; - try - { - sc = new SignatureContext(payload); - } - catch (InvalidOperationException) - { - return; - } - wallet.Sign(sc); - sc.Signable.Scripts = sc.GetScripts(); - LocalNode.Relay(payload); - } - - private void StartMine() - { - Program.Log($"{nameof(StartMine)}"); - ShowPrompt = false; - timer = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite); - Blockchain.PersistCompleted += Blockchain_PersistCompleted; - LocalNode.NewInventory += LocalNode_NewInventory; - InitializeConsensus(0); - } - } -} +using AntShares.Core; +using AntShares.Core.Scripts; +using AntShares.Network; +using AntShares.Network.Payloads; +using AntShares.Wallets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; + +namespace AntShares.Consensus +{ + public class ConsensusService : IDisposable + { + private ConsensusContext context = new ConsensusContext(); + private LocalNode localNode; + private Wallet wallet; + private Timer timer; + private uint timer_height; + private byte timer_view; + private DateTime block_received_time; + private string log_dictionary; + private bool started = false; + + public ConsensusService(LocalNode localNode, Wallet wallet, string log_dictionary = null) + { + this.localNode = localNode; + this.wallet = wallet; + this.timer = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite); + this.log_dictionary = log_dictionary; + } + + private bool AddTransaction(Transaction tx) + { + Log($"{nameof(AddTransaction)} hash:{tx.Hash}"); + if (context.Transactions.SelectMany(p => p.Value.GetAllInputs()).Intersect(tx.GetAllInputs()).Count() > 0 || + Blockchain.Default.ContainsTransaction(tx.Hash) || + !tx.Verify()) + { + Log($"failed hash:{tx.Hash}"); + RequestChangeView(); + return false; + } + context.Transactions[tx.Hash] = tx; + if (context.TransactionHashes.Length == context.Transactions.Count) + { + if (Blockchain.GetMinerAddress(Blockchain.Default.GetMiners(context.Transactions.Values).ToArray()).Equals(context.NextMiner)) + { + Log($"SendPerpareResponse"); + context.State |= ConsensusState.SignatureSent; + context.Signatures[context.MinerIndex] = context.MakeHeader().Sign(wallet.GetAccount(context.Miners[context.MinerIndex])); + SignAndRelay(context.MakePerpareResponse(context.Signatures[context.MinerIndex])); + CheckSignatures(); + } + else + { + RequestChangeView(); + return false; + } + } + return true; + } + + private void Blockchain_PersistCompleted(object sender, Block block) + { + Log($"{nameof(Blockchain_PersistCompleted)} hash:{block.Hash}"); + block_received_time = DateTime.Now; + InitializeConsensus(0); + } + + private void CheckExpectedView(byte view_number) + { + if (context.ViewNumber == view_number) return; + if (context.ExpectedView.Count(p => p == view_number) >= context.M) + { + InitializeConsensus(view_number); + } + } + + private void CheckSignatures() + { + if (context.Signatures.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p))) + { + Log($"{nameof(CheckSignatures)} {context.Signatures.Count(p => p != null)}/{context.M}"); + Contract contract = Contract.CreateMultiSigContract(context.Miners[context.MinerIndex].EncodePoint(true).ToScriptHash(), context.M, context.Miners); + Block block = context.MakeHeader(); + SignatureContext sc = new SignatureContext(block); + for (int i = 0; i < context.Miners.Length; i++) + if (context.Signatures[i] != null) + sc.Add(contract, context.Miners[i], context.Signatures[i]); + sc.Signable.Scripts = sc.GetScripts(); + block.Transactions = context.TransactionHashes.Select(p => context.Transactions[p]).ToArray(); + Log($"RelayBlock hash:{block.Hash}"); + if (!localNode.Relay(block)) + Log($"failed hash:{block.Hash}"); + context.State |= ConsensusState.BlockSent; + } + } + + private MinerTransaction CreateMinerTransaction(IEnumerable transactions, uint height, ulong nonce) + { + Fixed8 amount_netfee = Block.CalculateNetFee(transactions); + TransactionOutput[] outputs = amount_netfee == Fixed8.Zero ? new TransactionOutput[0] : new[] { new TransactionOutput + { + AssetId = Blockchain.AntCoin.Hash, + Value = amount_netfee, + ScriptHash = wallet.GetContracts().First().ScriptHash + } }; + return new MinerTransaction + { + Nonce = (uint)(nonce % (uint.MaxValue + 1ul)), + Attributes = new TransactionAttribute[0], + Inputs = new TransactionInput[0], + Outputs = outputs, + Scripts = new Script[0] + }; + } + + public void Dispose() + { + Log("OnStop"); + if (timer != null) timer.Dispose(); + if (started) + { + Blockchain.PersistCompleted -= Blockchain_PersistCompleted; + LocalNode.NewInventory -= LocalNode_NewInventory; + } + } + + private static ulong GetNonce() + { + byte[] nonce = new byte[sizeof(ulong)]; + Random rand = new Random(); + rand.NextBytes(nonce); + return BitConverter.ToUInt64(nonce, 0); + } + + private void InitializeConsensus(byte view_number) + { + lock (context) + { + if (view_number == 0) + context.Reset(wallet); + else + context.ChangeView(view_number); + if (context.MinerIndex < 0) return; + Log($"{nameof(InitializeConsensus)} h:{context.Height} v:{view_number} i:{context.MinerIndex} s:{(context.MinerIndex == context.PrimaryIndex ? ConsensusState.Primary : ConsensusState.Backup)}"); + if (context.MinerIndex == context.PrimaryIndex) + { + context.State |= ConsensusState.Primary; + timer_height = context.Height; + 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.Height; + timer_view = view_number; + timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (view_number + 1)), Timeout.InfiniteTimeSpan); + } + } + } + + private void LocalNode_NewInventory(object sender, IInventory 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); + } + } + } + + private void Log(string message) + { + DateTime now = DateTime.Now; + string line = $"[{now.TimeOfDay:hh\\:mm\\:ss}] {message}"; + Console.WriteLine(line); + if (string.IsNullOrEmpty(log_dictionary)) return; + lock (log_dictionary) + { + Directory.CreateDirectory(log_dictionary); + string path = Path.Combine(log_dictionary, $"{now:yyyy-MM-dd}.log"); + File.AppendAllLines(path, new[] { line }); + } + } + + private void OnChangeViewReceived(ConsensusPayload payload, ChangeView message) + { + Log($"{nameof(OnChangeViewReceived)} h:{payload.Height} v:{message.ViewNumber} i:{payload.MinerIndex} nv:{message.NewViewNumber}"); + if (message.NewViewNumber <= context.ExpectedView[payload.MinerIndex]) + return; + context.ExpectedView[payload.MinerIndex] = message.NewViewNumber; + CheckExpectedView(message.NewViewNumber); + } + + 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.NextMiner = message.NextMiner; + context.TransactionHashes = message.TransactionHashes; + context.Transactions = new Dictionary(); + if (!context.MakeHeader().VerifySignature(context.Miners[payload.MinerIndex], message.Signature)) return; + context.Signatures = new byte[context.Miners.Length][]; + context.Signatures[payload.MinerIndex] = message.Signature; + if (!AddTransaction(message.MinerTransaction)) return; + Dictionary mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash); + foreach (UInt256 hash in context.TransactionHashes.Skip(1)) + if (mempool.ContainsKey(hash)) + if (!AddTransaction(mempool[hash])) + return; + LocalNode.AllowHashes(context.TransactionHashes.Except(context.Transactions.Keys)); + if (context.Transactions.Count < context.TransactionHashes.Length) + localNode.SynchronizeMemoryPool(); + } + + 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(); + } + + private void OnTimeout(object state) + { + Log($"{nameof(OnTimeout)} h:{timer_height} v:{timer_view} state:{context.State}"); + lock (context) + { + if (timer_height != context.Height || timer_view != context.ViewNumber) + { + Log($"ignored"); + return; + } + if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent)) + { + Log($"SendPerpareRequest h:{timer_height} v:{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 transactions = LocalNode.GetMemoryPool().ToList(); + transactions.Insert(0, CreateMinerTransaction(transactions, context.Height, context.Nonce)); + context.TransactionHashes = transactions.Select(p => p.Hash).ToArray(); + context.Transactions = transactions.ToDictionary(p => p.Hash); + context.NextMiner = Blockchain.GetMinerAddress(Blockchain.Default.GetMiners(transactions).ToArray()); + context.Signatures[context.MinerIndex] = context.MakeHeader().Sign(wallet.GetAccount(context.Miners[context.MinerIndex])); + } + SignAndRelay(context.MakePerpareRequest()); + 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(); + } + } + } + + private void RequestChangeView() + { + context.ExpectedView[context.MinerIndex]++; + Log($"{nameof(RequestChangeView)} h:{context.Height} v:{context.ViewNumber} nv:{context.ExpectedView[context.MinerIndex]} state:{context.State}"); + timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (context.ExpectedView[context.MinerIndex] + 1)), Timeout.InfiniteTimeSpan); + SignAndRelay(context.MakeChangeView()); + CheckExpectedView(context.ExpectedView[context.MinerIndex]); + } + + private void SignAndRelay(ConsensusPayload payload) + { + SignatureContext sc; + try + { + sc = new SignatureContext(payload); + } + catch (InvalidOperationException) + { + return; + } + wallet.Sign(sc); + sc.Signable.Scripts = sc.GetScripts(); + localNode.Relay(payload); + } + + public void Start() + { + Log("OnStart"); + started = true; + Blockchain.PersistCompleted += Blockchain_PersistCompleted; + LocalNode.NewInventory += LocalNode_NewInventory; + InitializeConsensus(0); + } + } +} diff --git a/Miner/Miner/Consensus/ConsensusState.cs b/AntSharesCore/Consensus/ConsensusState.cs similarity index 84% rename from Miner/Miner/Consensus/ConsensusState.cs rename to AntSharesCore/Consensus/ConsensusState.cs index 4b30c05fa7..1926155c1c 100644 --- a/Miner/Miner/Consensus/ConsensusState.cs +++ b/AntSharesCore/Consensus/ConsensusState.cs @@ -1,16 +1,16 @@ -using System; - -namespace AntShares.Miner.Consensus -{ - [Flags] - internal enum ConsensusState : byte - { - Initial = 0x00, - Primary = 0x01, - Backup = 0x02, - RequestSent = 0x04, - RequestReceived = 0x08, - SignatureSent = 0x10, - BlockSent = 0x20, - } -} +using System; + +namespace AntShares.Consensus +{ + [Flags] + internal enum ConsensusState : byte + { + Initial = 0x00, + Primary = 0x01, + Backup = 0x02, + RequestSent = 0x04, + RequestReceived = 0x08, + SignatureSent = 0x10, + BlockSent = 0x20, + } +} diff --git a/Miner/Miner/Consensus/PerpareRequest.cs b/AntSharesCore/Consensus/PerpareRequest.cs similarity index 94% rename from Miner/Miner/Consensus/PerpareRequest.cs rename to AntSharesCore/Consensus/PerpareRequest.cs index e7fd7f1a8b..69c411e915 100644 --- a/Miner/Miner/Consensus/PerpareRequest.cs +++ b/AntSharesCore/Consensus/PerpareRequest.cs @@ -1,46 +1,46 @@ -using AntShares.Core; -using AntShares.IO; -using System; -using System.IO; -using System.Linq; - -namespace AntShares.Miner.Consensus -{ - internal class PerpareRequest : ConsensusMessage - { - public ulong Nonce; - public UInt160 NextMiner; - public UInt256[] TransactionHashes; - public MinerTransaction MinerTransaction; - public byte[] Signature; - - public PerpareRequest() - : base(ConsensusMessageType.PerpareRequest) - { - } - - public override void Deserialize(BinaryReader reader) - { - base.Deserialize(reader); - Nonce = reader.ReadUInt64(); - NextMiner = reader.ReadSerializable(); - TransactionHashes = reader.ReadSerializableArray(); - if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) - throw new FormatException(); - MinerTransaction = reader.ReadSerializable(); - if (MinerTransaction.Hash != TransactionHashes[0]) - throw new FormatException(); - Signature = reader.ReadBytes(64); - } - - public override void Serialize(BinaryWriter writer) - { - base.Serialize(writer); - writer.Write(Nonce); - writer.Write(NextMiner); - writer.Write(TransactionHashes); - writer.Write(MinerTransaction); - writer.Write(Signature); - } - } -} +using AntShares.Core; +using AntShares.IO; +using System; +using System.IO; +using System.Linq; + +namespace AntShares.Consensus +{ + internal class PerpareRequest : ConsensusMessage + { + public ulong Nonce; + public UInt160 NextMiner; + public UInt256[] TransactionHashes; + public MinerTransaction MinerTransaction; + public byte[] Signature; + + public PerpareRequest() + : base(ConsensusMessageType.PerpareRequest) + { + } + + public override void Deserialize(BinaryReader reader) + { + base.Deserialize(reader); + Nonce = reader.ReadUInt64(); + NextMiner = reader.ReadSerializable(); + TransactionHashes = reader.ReadSerializableArray(); + if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) + throw new FormatException(); + MinerTransaction = reader.ReadSerializable(); + if (MinerTransaction.Hash != TransactionHashes[0]) + throw new FormatException(); + Signature = reader.ReadBytes(64); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(Nonce); + writer.Write(NextMiner); + writer.Write(TransactionHashes); + writer.Write(MinerTransaction); + writer.Write(Signature); + } + } +} diff --git a/Miner/Miner/Consensus/PerpareResponse.cs b/AntSharesCore/Consensus/PerpareResponse.cs similarity index 89% rename from Miner/Miner/Consensus/PerpareResponse.cs rename to AntSharesCore/Consensus/PerpareResponse.cs index 21777db1ae..1afb3a0054 100644 --- a/Miner/Miner/Consensus/PerpareResponse.cs +++ b/AntSharesCore/Consensus/PerpareResponse.cs @@ -1,26 +1,26 @@ -using System.IO; - -namespace AntShares.Miner.Consensus -{ - internal class PerpareResponse : ConsensusMessage - { - public byte[] Signature; - - public PerpareResponse() - : base(ConsensusMessageType.PerpareResponse) - { - } - - public override void Deserialize(BinaryReader reader) - { - base.Deserialize(reader); - Signature = reader.ReadBytes(64); - } - - public override void Serialize(BinaryWriter writer) - { - base.Serialize(writer); - writer.Write(Signature); - } - } -} +using System.IO; + +namespace AntShares.Consensus +{ + internal class PerpareResponse : ConsensusMessage + { + public byte[] Signature; + + public PerpareResponse() + : base(ConsensusMessageType.PerpareResponse) + { + } + + public override void Deserialize(BinaryReader reader) + { + base.Deserialize(reader); + Signature = reader.ReadBytes(64); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(Signature); + } + } +} diff --git a/AntSharesCore/Wallets/Wallet.cs b/AntSharesCore/Wallets/Wallet.cs index 01a6a0ce35..c2f391d498 100644 --- a/AntSharesCore/Wallets/Wallet.cs +++ b/AntSharesCore/Wallets/Wallet.cs @@ -188,9 +188,7 @@ private static Fixed8 CalculateClaimAmountInternal(IEnumerable unclai public bool ChangePassword(string password_old, string password_new) { - byte[] passwordHash = LoadStoredData("PasswordHash"); - if (!passwordHash.SequenceEqual(password_old.ToAesKey().Sha256())) - return false; + if (!VerifyPassword(password_old)) return false; byte[] passwordKey = password_new.ToAesKey(); using (new ProtectedMemoryContext(masterKey, MemoryProtectionScope.SameProcess)) { @@ -736,5 +734,15 @@ public static UInt160 ToScriptHash(string address) throw new FormatException(); return new UInt160(data.Skip(1).Take(20).ToArray()); } + + public bool VerifyPassword(string password) + { + return password.ToAesKey().Sha256().SequenceEqual(LoadStoredData("PasswordHash")); + } + + public bool VerifyPassword(SecureString password) + { + return password.ToAesKey().Sha256().SequenceEqual(LoadStoredData("PasswordHash")); + } } } diff --git a/AntSharesDaemon/AntSharesDaemon.csproj b/AntSharesDaemon/AntSharesDaemon.csproj index 84dd2d146a..33c0ecbdaf 100644 --- a/AntSharesDaemon/AntSharesDaemon.csproj +++ b/AntSharesDaemon/AntSharesDaemon.csproj @@ -40,6 +40,7 @@ + diff --git a/Miner/Helper.cs b/AntSharesDaemon/Helper.cs similarity index 96% rename from Miner/Helper.cs rename to AntSharesDaemon/Helper.cs index ccec336c6e..7549c67a6b 100644 --- a/Miner/Helper.cs +++ b/AntSharesDaemon/Helper.cs @@ -1,39 +1,39 @@ -using System; -using System.Runtime.InteropServices; -using System.Security; - -namespace AntShares -{ - internal static class Helper - { - public static bool CompareTo(this SecureString s1, SecureString s2) - { - if (s1.Length != s2.Length) - return false; - IntPtr p1 = IntPtr.Zero; - IntPtr p2 = IntPtr.Zero; - try - { - p1 = Marshal.SecureStringToGlobalAllocAnsi(s1); - p2 = Marshal.SecureStringToGlobalAllocAnsi(s2); - int i = 0; - while (true) - { - byte b1 = Marshal.ReadByte(p1, i); - byte b2 = Marshal.ReadByte(p2, i++); - if (b1 == 0 && b2 == 0) - return true; - if (b1 != b2) - return false; - if (b1 == 0 || b2 == 0) - return false; - } - } - finally - { - Marshal.ZeroFreeGlobalAllocAnsi(p1); - Marshal.ZeroFreeGlobalAllocAnsi(p2); - } - } - } -} +using System; +using System.Runtime.InteropServices; +using System.Security; + +namespace AntShares +{ + internal static class Helper + { + public static bool CompareTo(this SecureString s1, SecureString s2) + { + if (s1.Length != s2.Length) + return false; + IntPtr p1 = IntPtr.Zero; + IntPtr p2 = IntPtr.Zero; + try + { + p1 = Marshal.SecureStringToGlobalAllocAnsi(s1); + p2 = Marshal.SecureStringToGlobalAllocAnsi(s2); + int i = 0; + while (true) + { + byte b1 = Marshal.ReadByte(p1, i); + byte b2 = Marshal.ReadByte(p2, i++); + if (b1 == 0 && b2 == 0) + return true; + if (b1 != b2) + return false; + if (b1 == 0 || b2 == 0) + return false; + } + } + finally + { + Marshal.ZeroFreeGlobalAllocAnsi(p1); + Marshal.ZeroFreeGlobalAllocAnsi(p2); + } + } + } +} diff --git a/AntSharesDaemon/Shell/MainService.cs b/AntSharesDaemon/Shell/MainService.cs index 853774aef6..64b3e9bf6b 100644 --- a/AntSharesDaemon/Shell/MainService.cs +++ b/AntSharesDaemon/Shell/MainService.cs @@ -1,16 +1,24 @@ -using AntShares.Core; +using AntShares.Consensus; +using AntShares.Core; using AntShares.Implementations.Blockchains.LevelDB; +using AntShares.Implementations.Wallets.EntityFramework; using AntShares.Network; using AntShares.Network.RPC; using AntShares.Properties; using AntShares.Services; +using AntShares.Wallets; using System; +using System.IO; +using System.Linq; +using System.Security; namespace AntShares.Shell { internal class MainService : ConsoleServiceBase { + private UserWallet wallet; private RpcServer rpc; + private ConsensusService consensus; protected LocalNode LocalNode { get; private set; } protected override string Prompt => "ant"; @@ -20,13 +28,228 @@ protected override bool OnCommand(string[] args) { switch (args[0].ToLower()) { + case "create": + return OnCreateCommand(args); + case "list": + return OnListCommand(args); + case "open": + return OnOpenCommand(args); + case "send": + return OnSendCommand(args); case "show": return OnShowCommand(args); + case "start": + return OnStartCommand(args); default: return base.OnCommand(args); } } + private bool OnCreateCommand(string[] args) + { + switch (args[1].ToLower()) + { + case "wallet": + return OnCreateWalletCommand(args); + default: + return base.OnCommand(args); + } + } + + private bool OnCreateWalletCommand(string[] args) + { + if (args.Length < 3) + { + Console.WriteLine("error"); + return true; + } + using (SecureString password = ReadSecureString("password")) + using (SecureString password2 = ReadSecureString("password")) + { + if (!password.CompareTo(password2)) + { + Console.WriteLine("error"); + return true; + } + wallet = UserWallet.Create(args[2], password); + foreach (Account account in wallet.GetAccounts()) + { + Console.WriteLine(account.PublicKey.EncodePoint(true).ToHexString()); + } + } + return true; + } + + private bool OnListCommand(string[] args) + { + switch (args[1].ToLower()) + { + case "account": + return OnListAccountCommand(args); + case "address": + return OnListAddressCommand(args); + case "asset": + return OnListAssetCommand(args); + default: + return base.OnCommand(args); + } + } + + private bool OnListAccountCommand(string[] args) + { + if (wallet == null) return true; + foreach (Account account in wallet.GetAccounts()) + { + Console.WriteLine(account.PublicKey); + } + return true; + } + + private bool OnListAddressCommand(string[] args) + { + if (wallet == null) return true; + foreach (Contract contract in wallet.GetContracts()) + { + Console.WriteLine($"{contract.Address}\t{contract.GetType()}"); + } + return true; + } + + private bool OnListAssetCommand(string[] args) + { + if (wallet == null) return true; + foreach (var item in wallet.FindCoins().Where(p => p.State == CoinState.Unspent || p.State == CoinState.Unconfirmed).GroupBy(p => p.AssetId, (k, g) => new + { + Asset = (RegisterTransaction)Blockchain.Default.GetTransaction(k), + Balance = g.Sum(p => p.Value), + Confirmed = g.Where(p => p.State == CoinState.Unspent).Sum(p => p.Value) + })) + { + Console.WriteLine($" id:{item.Asset.Hash}"); + Console.WriteLine($" name:{item.Asset.GetName()}"); + Console.WriteLine($" balance:{item.Balance}"); + Console.WriteLine($"confirmed:{item.Confirmed}"); + Console.WriteLine(); + } + return true; + } + + private bool OnOpenCommand(string[] args) + { + switch (args[1].ToLower()) + { + case "wallet": + return OnOpenWalletCommand(args); + default: + return base.OnCommand(args); + } + } + + //TODO: 目前没有想到其它安全的方法来保存密码 + //所以只能暂时手动输入,但如此一来就不能以服务的方式启动了 + //未来再想想其它办法,比如采用智能卡之类的 + private bool OnOpenWalletCommand(string[] args) + { + if (args.Length < 3) + { + Console.WriteLine("error"); + return true; + } + using (SecureString password = ReadSecureString("password")) + { + if (password.Length == 0) + { + Console.WriteLine("cancelled"); + return true; + } + try + { + wallet = UserWallet.Open(args[2], password); + } + catch + { + Console.WriteLine($"failed to open file \"{args[2]}\""); + return true; + } + } + return true; + } + + private bool OnSendCommand(string[] args) + { + if (wallet == null) + { + Console.WriteLine("You have to open the wallet first."); + return true; + } + if (args.Length < 4 || args.Length > 5) + { + Console.WriteLine("error"); + return true; + } + UInt256 assetId; + switch (args[1].ToLower()) + { + case "ans": + assetId = Blockchain.AntShare.Hash; + break; + case "anc": + assetId = Blockchain.AntCoin.Hash; + break; + default: + assetId = UInt256.Parse(args[1]); + break; + } + UInt160 scriptHash = Wallet.ToScriptHash(args[2]); + Fixed8 value = Fixed8.Parse(args[3]); + Fixed8 fee = args.Length >= 5 ? Fixed8.Parse(args[4]) : Fixed8.Zero; + ContractTransaction tx = wallet.MakeTransaction(new ContractTransaction + { + Outputs = new[] + { + new TransactionOutput + { + AssetId = assetId, + Value = value, + ScriptHash = scriptHash + } + } + }, fee); + if (tx == null) + { + Console.WriteLine("Insufficient funds"); + return true; + } + using (SecureString password = ReadSecureString("password")) + { + if (password.Length == 0) + { + Console.WriteLine("cancelled"); + return true; + } + if (!wallet.VerifyPassword(password)) + { + Console.WriteLine("Incorrect password"); + return true; + } + } + SignatureContext context = new SignatureContext(tx); + wallet.Sign(context); + if (context.Completed) + { + tx.Scripts = context.GetScripts(); + wallet.SaveTransaction(tx); + LocalNode.Relay(tx); + Console.WriteLine($"TXID: {tx.Hash}"); + } + else + { + Console.WriteLine("SignatureContext:"); + Console.WriteLine(context.ToString()); + } + return true; + } + private bool OnShowCommand(string[] args) { switch (args[1].ToLower()) @@ -79,8 +302,34 @@ protected internal override void OnStart(string[] args) } } + private bool OnStartCommand(string[] args) + { + switch (args[1].ToLower()) + { + case "consensus": + return OnStartConsensusCommand(args); + default: + return base.OnCommand(args); + } + } + + private bool OnStartConsensusCommand(string[] args) + { + if (wallet == null) + { + Console.WriteLine("You have to open the wallet first."); + return true; + } + string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); + consensus = new ConsensusService(LocalNode, wallet, log_dictionary); + ShowPrompt = false; + consensus.Start(); + return true; + } + protected internal override void OnStop() { + if (consensus != null) consensus.Dispose(); if (rpc != null) rpc.Dispose(); LocalNode.Dispose(); Blockchain.Default.Dispose(); diff --git a/Miner/Algebra/FiniteFieldPoint.cs b/Miner/Algebra/FiniteFieldPoint.cs deleted file mode 100644 index e16278a007..0000000000 --- a/Miner/Algebra/FiniteFieldPoint.cs +++ /dev/null @@ -1,153 +0,0 @@ -using AntShares.IO; -using System; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Numerics; -using System.Text; -using System.Text.RegularExpressions; - -namespace AntShares.Algebra -{ - /// - /// Represents a single 2D point using finite field polynomials. - /// - public class FiniteFieldPoint : ISerializable - { - public FiniteFieldPolynomial X { get; private set; } - public FiniteFieldPolynomial Y { get; private set; } - - public FiniteFieldPoint(FiniteFieldPolynomial x, FiniteFieldPolynomial y) - { - X = x; - Y = y; - } - - public void Deserialize(BinaryReader reader) - { - FiniteFieldPolynomial x, y; - DeserializeFrom(reader, out x, out y); - this.X = x; - this.Y = y; - } - - public static FiniteFieldPoint DeserializeFrom(BinaryReader reader) - { - FiniteFieldPolynomial x, y; - DeserializeFrom(reader, out x, out y); - return new FiniteFieldPoint(x, y); - } - - public static FiniteFieldPoint DeserializeFrom(byte[] value) - { - using (MemoryStream ms = new MemoryStream(value, false)) - using (BinaryReader reader = new BinaryReader(ms)) - { - return DeserializeFrom(reader); - } - } - - private static void DeserializeFrom(BinaryReader reader, out FiniteFieldPolynomial x, out FiniteFieldPolynomial y) - { - int x_i = (int)reader.ReadVarInt(int.MaxValue); - byte[] y_b = reader.ReadVarBytes(); - IrreduciblePolynomial irp = new IrreduciblePolynomial(y_b.Length * 8); - x = new FiniteFieldPolynomial(irp, x_i); - y = new FiniteFieldPolynomial(irp, y_b.ToBigIntegerFromBigEndianUnsignedBytes()); - } - - public static FiniteFieldPoint Parse(string s) - { - FiniteFieldPoint result; - if (!TryParse(s, out result)) - { - throw new ArgumentException(); - } - - return result; - } - - public void Serialize(BinaryWriter writer) - { - int expectedByteCount = Y.PrimePolynomial.SizeInBytes; - byte[] pointBytes = Y.PolynomialValue.ToUnsignedBigEndianBytes(); - writer.WriteVarInt((long)X.PolynomialValue); - writer.WriteVarInt(expectedByteCount); - writer.Write(new byte[expectedByteCount - pointBytes.Length]); - writer.Write(pointBytes); - } - - public override string ToString() - { - return ToString((int)X.PolynomialValue); - } - - public string ToString(int totalPoints) - { - var sb = new StringBuilder(); - // How many decimal digits do the total points take up? - - for (int remainder = totalPoints; remainder > 0; remainder /= 10) - { - sb.Append('0'); - } - - string format = sb.ToString(); - - string shareNumber = ((long)X.PolynomialValue).ToString(format); - - - var expectedByteCount = Y.PrimePolynomial.SizeInBytes; - var pointBytes = Y.PolynomialValue.ToUnsignedBigEndianBytes(); - - // Occasionally, the value won't fill all bytes, so we need to prefix with 0's as needed - var prefixedPointBytes = Enumerable.Repeat((byte)0, expectedByteCount - pointBytes.Length).Concat(pointBytes); - - // To hex string on its own just wasn't working right - string shareValue = String.Join("", prefixedPointBytes.Select(b => b.ToString("x2"))); - return shareNumber + "-" + shareValue; - } - - public static bool TryParse(string s, out FiniteFieldPoint result) - { - var match = Regex.Match(s, @"(?[0-9]+)-(?[0-9a-fA-F]+)"); - - if (!match.Success) - { - result = null; - return false; - } - - try - { - var xString = match.Groups["x"].Value.ToLowerInvariant(); - var yString = match.Groups["y"].Value.ToLowerInvariant(); - - // Each hex letter makes up 4 bits, so to get the degree in bits - // we multiply by 4 - - int polynomialDegree = yString.Length * 4; - - var irp = new IrreduciblePolynomial(polynomialDegree); - - var x = new FiniteFieldPolynomial(irp, BigInteger.Parse(xString)); - - // get bytes - var bigEndianBytes = new byte[yString.Length / 2]; - for (int i = 0; i < yString.Length; i += 2) - { - bigEndianBytes[i / 2] = Byte.Parse(yString.Substring(i, 2), NumberStyles.HexNumber); - } - var y = new FiniteFieldPolynomial(irp, bigEndianBytes.ToBigIntegerFromBigEndianUnsignedBytes()); - - result = new FiniteFieldPoint(x, y); - return true; - } - catch - { - result = null; - return false; - } - } - } -} diff --git a/Miner/Algebra/FiniteFieldPolynomial.cs b/Miner/Algebra/FiniteFieldPolynomial.cs deleted file mode 100644 index 9884eac8de..0000000000 --- a/Miner/Algebra/FiniteFieldPolynomial.cs +++ /dev/null @@ -1,209 +0,0 @@ -using System.Numerics; - -namespace AntShares.Algebra -{ - /// - /// Represents a polynomial modulo an irreducible polynomial (in a finite field). - /// - public class FiniteFieldPolynomial - { - private readonly IrreduciblePolynomial _PrimePolynomial; - private readonly BigInteger _PolynomialSetCoefficients; - - public FiniteFieldPolynomial(IrreduciblePolynomial primePolynomial, BigInteger polynomial) - { - _PrimePolynomial = primePolynomial; - _PolynomialSetCoefficients = polynomial; - } - - public FiniteFieldPolynomial(IrreduciblePolynomial primePolynomial, params int[] setCoefficients) - { - _PrimePolynomial = primePolynomial; - - _PolynomialSetCoefficients = BigInteger.Zero; - for (int i = 0; i < setCoefficients.Length; i++) - { - _PolynomialSetCoefficients = _PolynomialSetCoefficients.SetBit(setCoefficients[i]); - } - } - - public FiniteFieldPolynomial Clone() - { - return new FiniteFieldPolynomial(_PrimePolynomial, _PolynomialSetCoefficients); - } - - public BigInteger PolynomialValue - { - get { return _PolynomialSetCoefficients; } - } - - - public IrreduciblePolynomial PrimePolynomial - { - get { return _PrimePolynomial; } - } - - public static FiniteFieldPolynomial EvaluateAt(long x, FiniteFieldPolynomial[] coefficients) - { - // Use Horner's Scheme: http://en.wikipedia.org/wiki/Horner_scheme - - FiniteFieldPolynomial xAsPoly = coefficients[0].GetValueInField(x); - - // assume the coefficient for highest monomial is 1 - FiniteFieldPolynomial result = xAsPoly.Clone(); - - for (int i = coefficients.Length - 1; i > 0; i--) - { - result = result + coefficients[i]; - result = result * xAsPoly; - } - - result = result + coefficients[0]; - - return result; - } - - public static FiniteFieldPolynomial operator +(FiniteFieldPolynomial left, FiniteFieldPolynomial right) - { - BigInteger result = left._PolynomialSetCoefficients ^ right._PolynomialSetCoefficients; - return new FiniteFieldPolynomial(left._PrimePolynomial, result); - } - - public static FiniteFieldPolynomial operator *(FiniteFieldPolynomial left, FiniteFieldPolynomial right) - { - // Use a modified version of the "peasant's algorithm": - // http://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication - // The invariant is that a * b + p must always equal the product. We keep - // doubling "a" and halving "b". If "b" is odd, then we add "a" to "p" - - BigInteger p = BigInteger.Zero; - BigInteger a = left._PolynomialSetCoefficients; - BigInteger b = right._PolynomialSetCoefficients; - - int degree = left._PrimePolynomial.Degree; - - BigInteger mask = (BigInteger.One << degree) - BigInteger.One; - - for (int i = 0; i < degree; i++) - { - if ((a == BigInteger.Zero) || (b == BigInteger.Zero)) - { - break; - } - - if (b.TestBit(0)) - { - // It's odd, add it - p = p ^ a; - } - - bool highBitSet = a.TestBit(degree - 1); - - // multiply a by "x" - - a = a << 1; - a = a & mask; - - if (highBitSet) - { - a = a ^ left._PrimePolynomial.PolynomialValue; - a = a & mask; - } - - b = b >> 1; - } - - p = p & mask; - - return new FiniteFieldPolynomial(left._PrimePolynomial, p); - } - - public FiniteFieldPolynomial GetInverse() - { - // We need to compute the inverse of the current polynomial - // modulo the irreducible polynomial. We'll do this with - // a simplified version of the Euclidean algorithm: - // http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Computing_a_multiplicative_inverse_in_a_finite_field - // Instead of allowing division by arbitrary polynomials such as - // x^4 + x^3 + 1, we'll always divide by monomials like x^4. - // This makes multiplication and division by using just shifts. - - BigInteger r_minus2 = _PrimePolynomial.PolynomialValue; - BigInteger r_minus1 = _PolynomialSetCoefficients; - BigInteger a_minus2 = BigInteger.Zero; - BigInteger a_minus1 = BigInteger.One; - - while (!r_minus1.Equals(BigInteger.One)) - { - // How much do I need to shift by? - int shiftAmount = r_minus2.GetBitLength() - r_minus1.GetBitLength(); - - if (shiftAmount < 0) - { - Swap(ref r_minus2, ref r_minus1); - Swap(ref a_minus2, ref a_minus1); - shiftAmount = -shiftAmount; - } - - // Now r_minus2 should be as big or bigger than r_minus1 - // q = BigInteger.One.ShiftLeft(shiftAmount) - BigInteger r_minus1TimesQ = r_minus1 << shiftAmount; - BigInteger r_new = r_minus1TimesQ ^ r_minus2; - - BigInteger a_new = (a_minus1 << shiftAmount) ^ a_minus2; - - r_minus2 = r_minus1; - r_minus1 = r_new; - a_minus2 = a_minus1; - a_minus1 = a_new; - } - - return new FiniteFieldPolynomial(_PrimePolynomial, a_minus1); - } - - public FiniteFieldPolynomial Zero - { - get { return GetValueInField(0); } - } - - public FiniteFieldPolynomial One - { - get { return GetValueInField(1); } - } - - private FiniteFieldPolynomial GetValueInField(long n) - { - return new FiniteFieldPolynomial(_PrimePolynomial, new BigInteger(n)); - } - - public override string ToString() - { - return _PolynomialSetCoefficients.ToPolynomialString(); - } - - private static void Swap(ref BigInteger a, ref BigInteger b) - { - var temp = b; - b = a; - a = temp; - } - - public override bool Equals(object obj) - { - var other = obj as FiniteFieldPolynomial; - if (other == null) - { - return base.Equals(obj); - } - - return (PrimePolynomial == other.PrimePolynomial) - && - (PolynomialValue.Equals(other.PolynomialValue)); - } - - public override int GetHashCode() - { - return PrimePolynomial.GetHashCode() ^ PolynomialValue.GetHashCode(); - } - } -} diff --git a/Miner/Algebra/IrreduciblePolynomial.cs b/Miner/Algebra/IrreduciblePolynomial.cs deleted file mode 100644 index 8d76f40668..0000000000 --- a/Miner/Algebra/IrreduciblePolynomial.cs +++ /dev/null @@ -1,397 +0,0 @@ -using System; -using System.Numerics; - -namespace AntShares.Algebra -{ - /// - /// Polynomials that are irreducible (for use with a finite field). - /// - public class IrreduciblePolynomial - { - private const int InnerTermsPerPolynomial = 3; - // pentanomials - // For details on where this came from, see my question on: - // http://math.stackexchange.com/questions/14787/finding-irreducible-polynomials-over-gf2-with-the-fewest-terms - // The larger ones came directly from "Table of Low-Weight Binary Irreducible Polynomials" by HP Research - private static readonly int[] _TermPowers = new[] { - 4, 3, 1, 5, 3, 1, 4, 3, 1, 7, 3, 2, 5, 4, 3, 5, 3, 2, 7, 4 - , 2, 4, 3, 1, // x^64 - 10, 9, 3, 9, 4, 2, 7, 6, 2, 10, 9, 6, 4, 3, 1, 5, 4, 3, 4, - 3, 1, 7, 2, 1, // x^128 - 5, 3, 2, 7, 4, 2, 6, 3, 2, 5, 3, 2, 15, 3, 2, 11, 3, 2, 9, - 8, 7, 7, 2, 1, // x^192 - 5, 3, 2, 9, 3, 1, 7, 3, 1, 9, 8, 3, 9, 4, 2, 8, 5, 3, 15, - 14, 10, 10, 5, 2, // x^256 - 9, 6, 2, 9, 3, 2, 9, 5, 2, 11, 10, 1, 7, 3, 2, 11, 2, 1, 9 - , 7, 4, 4, 3, 1, // x^320 - 8, 3, 1, 7, 4, 1, 7, 2, 1, 13, 11, 6, 5, 3, 2, 7, 3, 2, 8, - 7, 5, 12, 3, 2, // x^384 - 13, 10, 6, 5, 3, 2, 5, 3, 2, 9, 5, 2, 9, 7, 2, 13, 4, 3, 4 - , 3, 1, 11, 6, 4, // x^448 - 18, 9, 6, 19, 18, 13, 11, 3, 2, 15, 9, 6, 4, 3, 1, 16, 5, - 2, 15, 14, 6, 8, 5, 2, // x^512 - 15, 11, 2, 11, 6, 2, 7, 5, 3, 8, 3, 1, 19, 16, 9, 11, 9, 6 - , 15, 7, 6, 13, 4, 3, // x^576 - 14, 13, 3, 13, 6, 3, 9, 5, 2, 19, 13, 6, 19, 10, 3, 11, 6, - 5, 9, 2, 1, 14, 3, 2, // x^640 - 13, 3, 1, 7, 5, 4, 11, 9, 8, 11, 6, 5, 23, 16, 9, 19, 14, - 6, 23, 10, 2, 8, 3, 2, // x^704 - 5, 4, 3, 9, 6, 4, 4, 3, 2, 13, 8, 6, 13, 11, 1, 13, 10, 3, - 11, 6, 5, 19, 17, 4, // x^768 - 15, 14, 7, 13, 9, 6, 9, 7, 3, 9, 7, 1, 14, 3, 2, 11, 8, 2, - 11, 6, 4, 13, 5, 2, // x^832 - 11, 5, 1, 11, 4, 1, 19, 10, 3, 21, 10, 6, 13, 3, 1, 15, 7, - 5, 19, 18, 10, 7, 5, 3, // x^896 - 12, 7, 2, 7, 5, 1, 14, 9, 6, 10, 3, 2, 15, 13, 12, 12, 11, - 9, 16, 9, 7, 12, 9, 3, // x^960 - 9, 5, 2, 17, 10, 6, 24, 9, 3, 17, 15, 13, 5, 4, 3, 19, 17, - 8, 15, 6, 3, 19, 6, 1, // x^1024 - 21, 15, 3, 15, 10, 8, 15, 7, 2, 11, 2, 1, 13, 11, 9, 19, 9 - , 8, 15, 9, 6, 22, 21, 10, // x^1088 - 24, 15, 6, 21, 9, 6, 15, 8, 6, 13, 9, 6, 7, 3, 1, 9, 4, 2, - 11, 9, 7, 15, 3, 2, // x^1152 - 15, 11, 2, 12, 7, 2, 11, 9, 3, 5, 3, 2, 9, 8, 7, 15, 9, 6, - 11, 10, 6, 27, 25, 9, // x^1216 - 12, 9, 7, 25, 10, 2, 17, 7, 5, 15, 5, 3, 31, 30, 2, 5, 3, - 2, 16, 9, 7, 12, 7, 5, // x^1280 - 23, 16, 6, 15, 14, 2, 20, 17, 15, 15, 14, 2, 12, 9, 3, 21, - 11, 3, 8, 3, 2, 15, 6, 1, // x^1344 - 17, 14, 6, 5, 3, 2, 15, 9, 5, 19, 18, 10, 11, 5, 1, 17, 15 - , 5, 8, 3, 1, 14, 13, 6, // x^1408 - 10, 9, 6, 11, 6, 2, 11, 10, 6, 14, 13, 7, 11, 3, 2, 9, 4, - 2, 12, 9, 3, 11, 4, 1, // x^1472 - 11, 10, 2, 9, 8, 6, 13, 11, 4, 8, 3, 2, 10, 9, 3, 13, 10, - 3, 18, 17, 7, 21, 6, 2, // x^1536 - 11, 7, 1, 19, 12, 2, 8, 5, 2, 21, 10, 7, 20, 9, 2, 21, 19, - 13, 12, 7, 5, 14, 11, 1, // x^1600 - 15, 13, 1, 13, 4, 3, 13, 11, 5, 17, 15, 3, 7, 5, 1, 18, 13 - , 1, 19, 15, 10, 17, 9, 6, // x^1664 - 5, 4, 3, 11, 6, 2, 15, 8, 6, 15, 6, 3, 14, 11, 3, 15, 12, - 5, 17, 14, 10, 11, 10, 5, // x^1728 - 19, 14, 6, 19, 18, 2, 6, 3, 2, 8, 3, 2, 25, 6, 5, 10, 9, 3 - , 23, 21, 6, 17, 14, 3, // x^1792 - 22, 5, 2, 19, 16, 9, 23, 18, 1, 7, 5, 1, 18, 13, 7, 21, 10 - , 2, 16, 13, 3, 11, 9, 4, // x^1856 - 11, 9, 1, 10, 5, 2, 15, 4, 2, 17, 13, 2, 26, 11, 2, 12, 11 - , 1, 20, 15, 10, 11, 3, 2, // x^1920 - 17, 16, 7, 15, 10, 1, 27, 22, 18, 15, 14, 6, 17, 15, 2, 25 - , 19, 14, 25, 19, 17, 13, 11, 5, // x^1984 - 6, 3, 2, 13, 10, 6, 26, 23, 13, 21, 15, 7, 40, 35, 9, 7, 6 - , 2, 7, 2, 1, 19, 14, 13, // x^2048 - 13, 12, 3, 17, 9, 2, 13, 10, 3, 4, 3, 1, 18, 11, 5, 19, 4, - 2, 19, 15, 9, 16, 13, 7, // x^2112 - 17, 14, 6, 23, 9, 1, 15, 12, 9, 13, 7, 3, 24, 13, 7, 31, - 25, 14, 11, 9, 3, 15, 8, 1, // x^2176 - 11, 10, 5, 8, 5, 3, 20, 15, 5, 21, 16, 6, 24, 7, 2, 21, 19 - , 5, 19, 17, 4, 23, 7, 1, // x^2240 - 9, 4, 3, 14, 9, 6, 15, 7, 2, 21, 10, 9, 13, 4, 2, 17, 16, - 7, 15, 10, 1, 8, 7, 5, // x^2304 - 19, 6, 4, 13, 11, 5, 15, 9, 2, 15, 10, 8, 27, 26, 14, 23, - 20, 2, 19, 10, 8, 13, 11, 8, // x^2368 - 7, 5, 4, 21, 19, 1, 31, 13, 3, 20, 19, 17, 23, 6, 4, 23, 6 - , 5, 21, 16, 6, 29, 22, 19, // x^2432 - 12, 7, 5, 21, 10, 4, 12, 5, 3, 5, 4, 3, 12, 3, 1, 20, 5, 2 - , 23, 13, 9, 12, 3, 1, // x^2496 - 19, 8, 6, 29, 21, 7, 31, 15, 13, 19, 9, 4, 21, 10, 9, 21, - 20, 6, 28, 3, 2, 9, 3, 1, // x^2560 - 8, 5, 2, 7, 2, 1, 25, 19, 12, 15, 12, 5, 14, 13, 7, 15, 11 - , 2, 17, 8, 7, 15, 10, 4, // x^2624 - 19, 5, 3, 23, 11, 9, 15, 8, 1, 19, 11, 5, 27, 21, 19, 18, - 7, 1, 15, 9, 4, 21, 10, 6, // x^2688 - 17, 15, 12, 12, 9, 7, 21, 12, 7, 25, 18, 1, 21, 7, 5, 16, - 3, 1, 19, 18, 10, 15, 4, 2, // x^2752 - 29, 26, 7, 25, 19, 15, 7, 3, 2, 29, 21, 15, 12, 7, 2, 17, - 14, 6, 15, 13, 1, 21, 19, 8, // x^2816 - 15, 14, 10, 27, 18, 1, 20, 15, 9, 15, 8, 1, 15, 13, 3, 21, - 17, 15, 21, 5, 2, 13, 10, 6, // x^2880 - 11, 4, 1, 29, 6, 1, 27, 15, 6, 16, 9, 2, 19, 9, 5, 24, 21, - 11, 5, 3, 2, 5, 3, 2, // x^2944 - 17, 13, 2, 12, 3, 2, 29, 27, 4, 21, 10, 3, 17, 9, 6, 23, 3 - , 1, 15, 12, 9, 15, 13, 1, // x^3008 - 38, 25, 9, 32, 3, 2, 17, 15, 4, 27, 21, 3, 18, 3, 2, 5, 4, - 3, 25, 11, 9, 11, 10, 5, // x^3072 - 21, 19, 16, 20, 13, 11, 33, 29, 14, 23, 9, 5, 17, 15, 1, - 18, 17, 11, 30, 19, 11, 15, 12, 10, // x^3136 - 23, 21, 8, 21, 17, 6, 7, 6, 2, 33, 31, 18, 13, 10, 5, 11, - 10, 2, 25, 8, 7, 11, 6, 4, // x^3200 - 16, 13, 3, 21, 11, 3, 23, 19, 1, 12, 9, 7, 12, 3, 2, 15, 8 - , 1, 31, 26, 2, 17, 5, 2, // x^3264 - 23, 10, 1, 16, 15, 6, 21, 18, 11, 19, 14, 13, 19, 17, 3, - 14, 9, 3, 17, 10, 4, 17, 9, 2, // x^3328 - 11, 10, 5, 30, 27, 15, 21, 20, 19, 18, 15, 5, 7, 5, 1, 11, - 9, 1, 21, 9, 3, 23, 13, 6, // x^3392 - 14, 13, 6, 16, 15, 6, 28, 27, 1, 22, 15, 6, 25, 2, 1, 27, - 16, 1, 17, 11, 6, 19, 18, 9, // x^3456 - 11, 6, 3, 17, 14, 7, 19, 15, 13, 12, 11, 1, 35, 21, 4, 23, - 17, 10, 37, 35, 6, 32, 29, 3, // x^3520 - 25, 18, 7, 12, 7, 5, 21, 14, 2, 15, 9, 6, 17, 3, 2, 21, 12 - , 10, 19, 10, 3, 25, 12, 10, // x^3584 - 38, 33, 14, 9, 5, 2, 15, 14, 10, 25, 18, 7, 29, 27, 12, 26 - , 17, 5, 20, 15, 10, 23, 7, 2, // x^3648 - 17, 12, 11, 35, 24, 14, 19, 17, 8, 14, 13, 7, 32, 13, 11, - 36, 33, 22, 14, 13, 1, 13, 12, 7, // x^3712 - 17, 15, 11, 9, 4, 2, 33, 22, 18, 27, 14, 2, 9, 4, 2, 23, 9 - , 1, 14, 7, 2, 7, 5, 4, // x^3776 - 29, 13, 6, 20, 7, 5, 24, 23, 21, 29, 18, 4, 19, 13, 9, 19, - 13, 2, 35, 13, 2, 27, 9, 1, // x^3840 - 29, 18, 13, 39, 25, 3, 19, 15, 9, 10, 3, 2, 27, 5, 1, 45, - 42, 6, 15, 7, 5, 17, 13, 2, // x^3904 - 24, 11, 2, 15, 13, 8, 8, 7, 5, 15, 5, 3, 31, 29, 28, 11, 6 - , 5, 29, 15, 2, 25, 18, 14, // x^3968 - 36, 3, 1, 19, 5, 2, 27, 8, 6, 31, 18, 17, 24, 9, 6, 33, 32 - , 23, 16, 9, 7, 15, 13, 6, // x^4032 - 29, 20, 15, 21, 5, 2, 21, 17, 6, 33, 29, 7, 13, 10, 6, 15, - 9, 6, 15, 7, 2, 27, 15, 1, // x^4096 - 30, 13, 3, 23, 12, 1, 26, 17, 9, 31, 2, 1, 31, 29, 15, 15, - 10, 1, 25, 13, 3, 27, 18, 12, // x^4160 - 17, 10, 6, 26, 15, 5, 29, 15, 7, 15, 11, 5, 12, 5, 2, 15, - 6, 3, 13, 3, 2, 8, 3, 2, // x^4224 - 18, 13, 7, 31, 6, 1, 11, 6, 2, 15, 13, 8, 15, 14, 5, 11, 8 - , 1, 17, 14, 5, 5, 4, 3, // x^4288 - 14, 5, 2, 12, 7, 2, 21, 5, 2, 21, 20, 14, 20, 17, 15, 18, - 11, 5, 8, 7, 5, 33, 27, 20, // x^4352 - 21, 4, 2, 27, 12, 6, 18, 7, 1, 27, 19, 17, 20, 19, 5, 37, - 35, 3, 9, 8, 7, 31, 10, 6, // x^4416 - 21, 19, 13, 25, 5, 3, 26, 21, 14, 11, 9, 8, 24, 9, 7, 13, - 3, 1, 30, 7, 2, 28, 21, 15, // x^4480 - 38, 35, 13, 17, 10, 7, 12, 9, 6, 12, 3, 1, 39, 25, 23, 23, - 13, 9, 25, 11, 7, 25, 14, 7, // x^4544 - 34, 27, 18, 14, 13, 7, 22, 17, 6, 26, 19, 9, 19, 15, 9, 21 - , 16, 11, 17, 14, 1, 23, 20, 13, // x^4608 - 27, 23, 5, 26, 23, 10, 19, 16, 2, 25, 8, 7, 8, 5, 3, 27, - 25, 4, 37, 6, 5, 27, 25, 23, // x^4672 - 10, 9, 3, 13, 7, 6, 18, 17, 11, 11, 8, 1, 25, 16, 6, 24, - 19, 9, 26, 21, 14, 15, 10, 1, // x^4736 - 19, 14, 6, 29, 5, 2, 28, 11, 9, 25, 17, 3, 27, 23, 6, 30, - 29, 7, 29, 18, 4, 29, 19, 11, // x^4800 - 13, 4, 2, 33, 31, 25, 25, 16, 3, 33, 30, 5, 25, 21, 2, 28, - 27, 6, 27, 23, 21, 29, 22, 17, // x^4864 - 24, 9, 2, 32, 21, 7, 35, 21, 8, 21, 19, 12, 27, 18, 15, 30 - , 29, 7, 11, 9, 5, 29, 9, 3, // x^4928 - 27, 22, 15, 19, 6, 4, 29, 11, 5, 25, 20, 6, 26, 25, 17, 42 - , 7, 1, 23, 16, 9, 15, 8, 6, // x^4992 - 17, 15, 7, 21, 10, 3, 15, 12, 9, 33, 23, 14, 25, 6, 2, 24, - 5, 3, 34, 15, 10, 22, 9, 6, // x^5056 - 21, 12, 11, 25, 5, 3, 21, 7, 6, 22, 21, 3, 19, 18, 13, 30, - 13, 2, 42, 33, 9, 33, 27, 5, // x^5120 - 24, 15, 6, 27, 25, 4, 15, 11, 5, 15, 8, 1, 35, 31, 13, 15, - 11, 5, 24, 21, 3, 20, 11, 5, // x^5184 - 11, 8, 2, 33, 27, 19, 23, 22, 2, 27, 19, 2, 29, 15, 1, 21, - 11, 2, 33, 27, 21, 27, 18, 1, // x^5248 - 9, 5, 2, 16, 11, 9, 29, 18, 10, 13, 11, 1, 11, 10, 1, 8, 3 - , 2, 27, 6, 5, 22, 3, 2, // x^5312 - 19, 17, 3, 30, 27, 9, 23, 21, 8, 17, 11, 10, 23, 20, 1, 19 - , 11, 1, 19, 18, 3, 7, 4, 1, // x^5376 - 17, 15, 4, 7, 3, 2, 33, 17, 3, 30, 23, 1, 34, 31, 19, 16, - 15, 13, 37, 34, 23, 24, 15, 10, // x^5440 - 43, 33, 15, 21, 14, 10, 15, 5, 2, 21, 15, 3, 13, 10, 3, 21 - , 19, 9, 13, 11, 4, 20, 19, 1, // x^5504 - 13, 11, 6, 10, 5, 2, 25, 18, 14, 20, 5, 3, 11, 10, 2, 15, - 9, 8, 55, 46, 10, 33, 22, 7, // x^5568 - 27, 23, 6, 13, 9, 7, 29, 20, 7, 8, 5, 3, 22, 5, 2, 30, 15, - 6, 21, 18, 14, 17, 15, 5, // x^5632 - 29, 27, 23, 21, 15, 8, 27, 12, 9, 31, 29, 11, 26, 25, 10, - 40, 17, 2, 41, 20, 11, 26, 21, 14, // x^5696 - 27, 25, 14, 10, 9, 3, 32, 11, 2, 25, 24, 7, 25, 18, 10, 21 - , 11, 8, 21, 20, 7, 29, 23, 10, // x^5760 - 21, 14, 3, 19, 12, 1, 25, 22, 6, 33, 13, 11, 25, 7, 6, 43, - 10, 1, 17, 15, 7, 23, 17, 10, // x^5824 - 21, 18, 13, 23, 14, 2, 19, 8, 6, 23, 15, 6, 27, 11, 10, 19 - , 15, 10, 21, 10, 3, 23, 10, 4, // x^5888 - 30, 23, 1, 32, 19, 5, 33, 22, 13, 16, 15, 6, 16, 7, 2, 27, - 4, 1, 23, 21, 14, 25, 23, 2, // x^5952 - 37, 35, 25, 21, 14, 4, 18, 9, 6, 17, 7, 1, 29, 9, 2, 23, - 21, 12, 30, 27, 15, 35, 34, 2, // x^6016 - 39, 33, 26, 44, 21, 14, 25, 11, 5, 17, 15, 8, 7, 6, 1, 23, - 18, 11, 28, 15, 13, 19, 8, 6, // x^6080 - 23, 10, 3, 20, 11, 2, 13, 11, 6, 35, 12, 1, 4, 3, 1, 34, - 15, 2, 17, 7, 5, 26, 7, 1, // x^6144 - 28, 27, 13, 38, 15, 10, 20, 11, 2, 29, 15, 1, 39, 13, 12, - 20, 5, 2, 29, 10, 7, 25, 23, 14, // x^6208 - 39, 30, 9, 13, 4, 2, 17, 3, 1, 11, 10, 2, 18, 7, 2, 11, 10 - , 5, 17, 16, 7, 17, 10, 6, // x^6272 - 9, 7, 5, 34, 25, 5, 35, 19, 10, 13, 3, 1, 35, 33, 14, 29, - 28, 10, 15, 6, 1, 22, 15, 9, // x^6336 - 21, 15, 2, 21, 11, 4, 13, 11, 1, 31, 9, 1, 28, 27, 5, 34, - 29, 7, 39, 34, 10, 37, 12, 3, // x^6400 - 31, 12, 10, 29, 15, 7, 29, 18, 5, 26, 13, 7, 21, 18, 14, - 25, 23, 8, 31, 25, 17, 25, 22, 6, // x^6464 - 31, 30, 2, 11, 10, 1, 21, 13, 7, 21, 5, 2, 23, 15, 9, 29, - 27, 13, 37, 29, 11, 16, 7, 2, // x^6528 - 25, 10, 9, 19, 15, 1, 27, 22, 6, 19, 13, 11, 19, 15, 1, 27 - , 25, 19, 37, 23, 7, 45, 42, 1, // x^6592 - 21, 19, 16, 9, 4, 2, 33, 9, 3, 15, 14, 9, 27, 20, 17, 43, - 32, 9, 25, 19, 16, 19, 15, 1, // x^6656 - 24, 15, 6, 26, 21, 5, 29, 7, 3, 55, 32, 9, 45, 19, 7, 11, - 10, 6, 31, 26, 2, 12, 9, 7, // x^6720 - 21, 8, 2, 27, 14, 2, 29, 21, 15, 11, 8, 2, 37, 15, 7, 18, - 15, 10, 25, 11, 6, 16, 15, 1, // x^6784 - 27, 25, 24, 26, 25, 1, 37, 19, 13, 22, 5, 2, 21, 14, 10, - 35, 32, 25, 14, 9, 3, 29, 22, 18, // x^6848 - 30, 29, 17, 11, 5, 2, 25, 13, 2, 31, 30, 19, 24, 11, 9, 29 - , 17, 11, 36, 13, 11, 25, 15, 12, // x^6912 - 8, 3, 1, 8, 7, 5, 37, 31, 30, 23, 21, 8, 32, 21, 19, 14, 9 - , 3, 35, 32, 17, 19, 18, 9, // x^6976 - 8, 3, 2, 27, 11, 9, 27, 26, 11, 33, 25, 6, 23, 10, 7, 22, - 15, 10, 19, 13, 9, 19, 18, 7, // x^7040 - 39, 17, 4, 27, 24, 10, 11, 5, 2, 37, 26, 17, 27, 18, 16, - 32, 5, 2, 27, 17, 13, 15, 10, 4, // x^7104 - 35, 5, 2, 17, 15, 5, 19, 13, 2, 16, 3, 2, 33, 13, 3, 37, - 23, 16, 27, 26, 9, 13, 10, 6, // x^7168 - 33, 31, 21, 33, 27, 2, 29, 14, 6, 29, 23, 3, 29, 23, 21, - 15, 8, 1, 15, 12, 10, 35, 12, 9, // x^7232 - 33, 14, 2, 17, 7, 4, 22, 21, 7, 41, 36, 19, 23, 10, 4, 37, - 6, 4, 25, 23, 17, 37, 7, 2, // x^7296 - 37, 30, 17, 25, 24, 3, 35, 28, 10, 41, 30, 26, 34, 21, 5, - 33, 28, 3, 20, 5, 3, 23, 18, 2, // x^7360 - 19, 13, 11, 41, 22, 16, 31, 26, 9, 33, 27, 21, 19, 9, 5, - 13, 3, 1, 35, 23, 9, 18, 13, 7, // x^7424 - 30, 19, 7, 22, 21, 15, 21, 20, 14, 27, 8, 1, 21, 18, 14, - 23, 13, 7, 32, 15, 2, 21, 16, 6, // x^7488 - 23, 21, 12, 45, 17, 2, 22, 21, 3, 19, 9, 7, 18, 13, 1, 42, - 21, 14, 23, 13, 7, 17, 8, 3, // x^7552 - 41, 21, 3, 15, 5, 3, 41, 40, 11, 51, 46, 10, 45, 10, 1, 19 - , 18, 2, 39, 25, 10, 31, 21, 14, // x^7616 - 9, 2, 1, 54, 3, 2, 29, 3, 2, 37, 33, 10, 30, 13, 7, 30, 23 - , 5, 39, 5, 1, 27, 9, 3, // x^7680 - 35, 16, 6, 17, 16, 15, 15, 12, 10, 27, 22, 5, 27, 25, 4, - 21, 6, 3, 22, 11, 3, 33, 28, 27, // x^7744 - 35, 30, 2, 32, 23, 21, 27, 18, 15, 41, 39, 36, 7, 4, 2, 47 - , 31, 29, 11, 10, 5, 25, 24, 10, // x^7808 - 20, 3, 2, 39, 36, 14, 37, 19, 3, 33, 29, 23, 34, 31, 21, - 12, 3, 2, 19, 13, 1, 27, 22, 18, // x^7872 - 25, 19, 17, 12, 9, 7, 45, 39, 7, 45, 34, 25, 7, 3, 2, 20, - 19, 5, 23, 15, 5, 40, 23, 21, // x^7936 - 14, 7, 1, 19, 13, 2, 19, 13, 12, 27, 13, 12, 44, 5, 3, 37, - 18, 2, 26, 25, 17, 16, 3, 1, // x^8000 - 23, 22, 17, 31, 30, 25, 21, 14, 11, 19, 15, 13, 39, 13, 7, - 30, 23, 3, 27, 16, 5, 27, 23, 9, // x^8064 - 23, 11, 6, 39, 14, 11, 25, 10, 8, 32, 11, 2, 30, 23, 17, - 15, 12, 2, 8, 3, 2, 25, 24, 19, // x^8128 - 11, 3, 2, 28, 27, 17, 29, 25, 14, 52, 45, 10, 25, 16, 6, - 43, 32, 21, 32, 27, 6, 9, 5, 2, // x^8192 - 18, 15, 3, 19, 13, 11, 27, 24, 17, 39, 36, 25, 22, 15, 9, - 14, 13, 7, 25, 15, 13, 32, 21, 14, // x^8256 - 15, 6, 3, 32, 25, 23, 30, 19, 9, 27, 5, 4, 37, 19, 6, 32, - 17, 15, 45, 44, 30, 41, 39, 5, // x^8320 - 37, 23, 14, 33, 10, 2, 27, 15, 1, 35, 18, 14, 15, 14, 5, - 35, 17, 4, 45, 39, 17, 19, 4, 2, // x^8384 - 17, 11, 1, 29, 28, 11, 20, 9, 2, 40, 33, 22, 33, 31, 28, - 17, 15, 13, 18, 9, 6, 21, 17, 6, // x^8448 - 15, 13, 8, 34, 15, 5, 30, 21, 5, 21, 6, 3, 13, 6, 3, 25, - 19, 3, 35, 24, 10, 33, 27, 4, // x^8512 - 28, 15, 13, 15, 4, 2, 19, 10, 3, 31, 5, 2, 29, 10, 1, 21, - 13, 3, 28, 25, 10, 19, 9, 1, // x^8576 - 32, 15, 13, 23, 5, 4, 21, 14, 3, 47, 44, 33, 22, 19, 11, 4 - , 3, 2, 41, 32, 3, 23, 10, 4, // x^8640 - 31, 17, 6, 39, 14, 4, 29, 19, 11, 29, 23, 12, 32, 7, 2, 25 - , 20, 7, 25, 20, 6, 39, 20, 2, // x^8704 - 30, 13, 3, 27, 17, 5, 13, 7, 1, 35, 33, 24, 45, 12, 11, 30 - , 29, 11, 27, 9, 4, 27, 10, 8, // x^8768 - 26, 19, 9, 26, 25, 7, 24, 9, 2, 25, 14, 6, 15, 9, 6, 17, 8 - , 6, 19, 14, 6, 15, 9, 6, // x^8832 - 33, 22, 16, 33, 4, 3, 14, 5, 2, 37, 12, 7, 51, 4, 2, 36, 9 - , 6, 43, 13, 9, 41, 10, 6, // x^8896 - 40, 25, 10, 18, 17, 1, 33, 32, 31, 35, 29, 2, 17, 3, 1, 39 - , 34, 1, 27, 14, 2, 12, 7, 5, // x^8960 - 29, 11, 10, 23, 8, 2, 9, 8, 6, 35, 6, 2, 28, 19, 17, 31, - 17, 7, 23, 21, 8, 32, 29, 11, // x^9024 - 45, 19, 1, 9, 6, 4, 23, 16, 10, 11, 3, 2, 33, 4, 2, 45, 38 - , 6, 17, 10, 7, 33, 31, 1, // x^9088 - 27, 26, 11, 47, 33, 24, 9, 7, 5, 35, 25, 5, 39, 25, 22, 21 - , 14, 1, 35, 25, 4, 33, 29, 7, // x^9152 - 22, 15, 3, 15, 10, 4, 43, 37, 30, 33, 26, 14, 21, 18, 13, - 31, 24, 2, 35, 10, 9, 21, 14, 8, // x^9216 - 35, 21, 7, 49, 18, 8, 17, 11, 7, 37, 18, 13, 19, 6, 4, 39, - 17, 14, 13, 4, 3, 23, 7, 2, // x^9280 - 49, 43, 18, 29, 17, 15, 27, 13, 9, 21, 19, 16, 55, 22, 8, - 21, 14, 8, 17, 5, 3, 51, 44, 5, // x^9344 - 31, 26, 15, 28, 23, 1, 38, 7, 1, 23, 5, 1, 17, 11, 6, 29, - 24, 11, 18, 13, 1, 28, 15, 6, // x^9408 - 19, 11, 6, 22, 9, 6, 52, 43, 25, 25, 22, 14, 23, 21, 20, - 35, 19, 5, 37, 18, 13, 45, 40, 15, // x^9472 - 18, 9, 2, 25, 12, 7, 29, 17, 15, 19, 15, 6, 39, 17, 16, 13 - , 5, 2, 37, 33, 22, 31, 26, 6, // x^9536 - 43, 32, 9, 11, 4, 1, 27, 13, 2, 49, 26, 14, 29, 25, 7, 36, - 29, 27, 15, 8, 1, 19, 6, 4, // x^9600 - 14, 13, 1, 25, 8, 2, 31, 17, 7, 30, 23, 5, 33, 7, 3, 31, - 24, 21, 19, 16, 2, 35, 21, 1, // x^9664 - 17, 9, 3, 25, 6, 2, 20, 9, 2, 36, 27, 21, 7, 3, 2, 27, 19, - 17, 37, 4, 2, 30, 5, 2, // x^9728 - 15, 7, 6, 36, 9, 2, 42, 17, 3, 56, 49, 47, 41, 23, 22, 24, - 19, 1, 38, 37, 9, 27, 26, 21, // x^9792 - 42, 41, 10, 43, 32, 21, 46, 33, 22, 13, 10, 3, 39, 37, 25, - 49, 47, 13, 25, 23, 10, 36, 15, 1, // x^9856 - 35, 32, 21, 13, 11, 3, 35, 28, 5, 33, 6, 4, 39, 38, 26, 21 - , 10, 2, 42, 35, 15, 49, 18, 14, // x^9920 - 39, 38, 31, 22, 21, 1, 15, 14, 6, 31, 30, 11, 30, 15, 10, - 36, 3, 2, 21, 19, 5, 27, 10, 7, // x^9984 - 7, 4, 2, 19, 13, 9 // x^10000 - }; - - public BigInteger PolynomialValue { get; private set; } - - public IrreduciblePolynomial(int degreeOfIrreduciblePolynomial) - { - if (!IsValidDegree(degreeOfIrreduciblePolynomial)) - { - throw new ArgumentException(); - } - - PolynomialValue = BigInteger.Zero.SetBit(degreeOfIrreduciblePolynomial); - - for (int i = 0; i < InnerTermsPerPolynomial; i++) - { - PolynomialValue = - PolynomialValue.SetBit( - _TermPowers[InnerTermsPerPolynomial * ((degreeOfIrreduciblePolynomial / 8) - 1) + i]); - } - - PolynomialValue = PolynomialValue.SetBit(0); - Degree = degreeOfIrreduciblePolynomial; - } - - public int Degree { get; private set; } - - public int SizeInBytes - { - get { return Degree / 8; } - } - - public static IrreduciblePolynomial CreateOfByteSize(int byteSize) - { - return new IrreduciblePolynomial(byteSize * 8); - } - - public static int MaxDegree - { - get { return (_TermPowers.Length / InnerTermsPerPolynomial) * 8; } - } - - public static bool IsValidDegree(int degree) - { - return (8 <= degree) && (degree <= MaxDegree) && ((degree % 8) == 0); - } - - public override string ToString() - { - return PolynomialValue.ToPolynomialString(); - } - - public override bool Equals(object obj) - { - var other = obj as IrreduciblePolynomial; - if (other == null) - { - return base.Equals(obj); - } - - return PolynomialValue.Equals(other.PolynomialValue); - } - - public override int GetHashCode() - { - return PolynomialValue.GetHashCode(); - } - } -} diff --git a/Miner/Algebra/LagrangeInterpolator.cs b/Miner/Algebra/LagrangeInterpolator.cs deleted file mode 100644 index ce3b8659d1..0000000000 --- a/Miner/Algebra/LagrangeInterpolator.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - -namespace AntShares.Algebra -{ - /// - /// Finds the y-intercept of a polynomial in a finite field. - /// - public class LagrangeInterpolator - { - public static FiniteFieldPolynomial EvaluateAtZero(IEnumerable points) - { - var originalPoints = points.ToArray(); - - if (originalPoints.Length == 0) - { - throw new ArgumentOutOfRangeException(); - } - - int threshold = originalPoints.Length; - // We need to "correct" these points by removing the high term monomial - var adjustedPoints = originalPoints.Select(p => AdjustPoint(threshold, p)).ToArray(); - - // Use Lagrange interpolating polynomials ( http://en.wikipedia.org/wiki/Lagrange_polynomial ) - // to solve: - - // (x-x2)(x-x3)...(x-xn) (x-x1)(x-x3)...(x-xn) - // P(x) = ------------------------ y1 + -------------------------- y2 + ... + - // (x1-x2)(x1-x3)...(x1-xn) (x2-x1)(x2-x3)...(x2-xn-1) - - // Simplifying things is that x is 0 since we want to find the constant term - - var fieldPoly = originalPoints[0].Y; - - var total = fieldPoly.Zero; - - for (int ixCurrentPoint = 0; ixCurrentPoint < threshold; ixCurrentPoint++) - { - var currentNumerator = fieldPoly.One; - var currentDenominator = fieldPoly.One; - var currentPoint = adjustedPoints[ixCurrentPoint]; - - for (int ixOtherPoint = 0; ixOtherPoint < threshold; ixOtherPoint++) - { - if (ixCurrentPoint == ixOtherPoint) - { - continue; - } - - // numerator needs multiplied by - // (0-x_i) = -x_i = x_i - // (since subtraction and addition are the same in GF[2] - currentNumerator *= adjustedPoints[ixOtherPoint].X; - currentDenominator *= (currentPoint.X + adjustedPoints[ixOtherPoint].X); - } - - // Dividing is just multiplying by the inverse - var denominatorInverse = currentDenominator.GetInverse(); - - var fraction = currentNumerator * denominatorInverse; - - // Now, multiply the fraction by the relevant y_i - var currentTermValue = fraction * currentPoint.Y; - total += currentTermValue; - } - - return total; - } - - private static FiniteFieldPoint AdjustPoint(int totalPoints, FiniteFieldPoint point) - { - var correction = new FiniteFieldPolynomial(point.Y.PrimePolynomial, BigInteger.One); - var correctionMultiplier = point.X; - - for (int i = 1; i <= totalPoints; i++) - { - correction = correction * correctionMultiplier; - } - - var newY = point.Y + correction; - return new FiniteFieldPoint(point.X, newY); - } - } -} diff --git a/Miner/App.config b/Miner/App.config deleted file mode 100644 index 2961d5c76b..0000000000 --- a/Miner/App.config +++ /dev/null @@ -1,29 +0,0 @@ - - - - -
- - - - - - - - - .\Chain - - - 10333 - - - - - - - - - - - - diff --git a/Miner/BigIntegerExtensions.cs b/Miner/BigIntegerExtensions.cs deleted file mode 100644 index 0e876a8e41..0000000000 --- a/Miner/BigIntegerExtensions.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Linq; -using System.Numerics; -using System.Text; - -namespace AntShares -{ - internal static class BigIntegerExtensions - { - public static BigInteger SetBit(this BigInteger n, int bit) - { - return n |= BigInteger.One << bit; - } - - public static bool TestBit(this BigInteger n, int bit) - { - return (n & (BigInteger.One << bit)) != 0; - } - - public static int GetBitLength(this BigInteger n) - { - var remainder = n; - int bits = 0; - while (remainder > 0) - { - remainder = remainder >> 1; - bits++; - } - - return bits; - } - - public static string ToPolynomialString(this BigInteger n) - { - var sb = new StringBuilder(); - for (int i = n.GetBitLength(); i >= 0; i--) - { - if (n.TestBit(i)) - { - if (sb.Length > 0) - { - sb.Append(" + "); - } - - sb.Append((i > 0) ? "x" : "1"); - - if (i > 1) - { - sb.Append("^"); - sb.Append(i); - } - } - } - - if (sb.Length == 0) - { - sb.Append("0"); - } - - return sb.ToString(); - } - - public static byte[] ToUnsignedLittleEndianBytes(this BigInteger n) - { - var byteArray = n.ToByteArray(); - if ((byteArray.Length > 1) && (byteArray[byteArray.Length - 1] == 0x00)) - { - var byteArrayMissingEnd = new byte[byteArray.Length - 1]; - Array.Copy(byteArray, byteArrayMissingEnd, byteArrayMissingEnd.Length); - return byteArrayMissingEnd; - } - return byteArray; - } - - public static byte[] ToUnsignedBigEndianBytes(this BigInteger n) - { - var bytes = n.ToUnsignedLittleEndianBytes(); - Array.Reverse(bytes); - return bytes; - } - - public static BigInteger ToBigIntegerFromLittleEndianUnsignedBytes(this byte[] bytes) - { - return new BigInteger(bytes.Concat(new byte[1]).ToArray()); - } - - public static BigInteger ToBigIntegerFromBigEndianUnsignedBytes(this byte[] bytes) - { - byte[] littleEndianBytes = bytes.Reverse().ToArray(); - return littleEndianBytes.ToBigIntegerFromLittleEndianUnsignedBytes(); - } - } -} diff --git a/Miner/Cryptography/Diffuser.cs b/Miner/Cryptography/Diffuser.cs deleted file mode 100644 index eee7f532fa..0000000000 --- a/Miner/Cryptography/Diffuser.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Numerics; - -namespace AntShares.Cryptography -{ - /// - /// Diffuses the bits of the number. - /// - internal abstract class Diffuser - { - public virtual BigInteger Scramble(BigInteger input, int rawByteLength) - { - return Scramble(input); - } - - protected virtual BigInteger Scramble(BigInteger input) - { - return input; - } - - public virtual BigInteger Unscramble(BigInteger input, int rawByteLength) - { - return Unscramble(input); - } - - protected virtual BigInteger Unscramble(BigInteger input) - { - return input; - } - } - - // NOTE: In order to achieve full compatibility with B. Poettering's "ssss-split" and - // "ssss-combine" programs, I (Jeff) had to look at B. Poettering's source code - // to see exactly how he diffused data using the XTEA algorithm. I reproduced the - // effective results using my own code below, but still had to look at his code. - // I asked for explicit permission from the author (B. Poettering) to release - // my derived code under the MIT license (instead of GPL) and was generously - // granted permission by him. For more license details, see License.txt included - // with this code. - internal class XteaDiffuser : Diffuser - { - private const int InnerRounds = 32; - private const int OuterRounds = 40; - private const UInt32 Delta = 0x9E3779B9; - private const UInt32 DecodeInitialSum = unchecked(InnerRounds * Delta); - - protected override BigInteger Scramble(BigInteger input) - { - int actualByteSize; - byte[] integerBytes = GetBigIntegerBytesWithLeastSignificantWordFirstUsing16BitMsbFirstWords(input, - out actualByteSize); - - for (int i = 0; i < (OuterRounds * actualByteSize); i += 2) - { - EncodeSlice(integerBytes, i, actualByteSize, EncipherBlock); - } - - return GetBigIntegerFromLeastSignificantWordsFirstWith16BitMsbFirstWords(integerBytes, actualByteSize); - } - - protected override BigInteger Unscramble(BigInteger input) - { - int actualByteSize; - byte[] integerBytes = GetBigIntegerBytesWithLeastSignificantWordFirstUsing16BitMsbFirstWords(input, - out actualByteSize); - - for (int i = (OuterRounds * actualByteSize) - 2; i >= 0; i -= 2) - { - EncodeSlice(integerBytes, i, actualByteSize, DecipherBlock); - } - - return GetBigIntegerFromLeastSignificantWordsFirstWith16BitMsbFirstWords(integerBytes, actualByteSize); - } - - // The whole point of the diffuser is to diffuse bits, that's why we'll pick least significant words - // with most significant word bits. This alone does some diffusion. - private static byte[] GetBigIntegerBytesWithLeastSignificantWordFirstUsing16BitMsbFirstWords(BigInteger input, - out int actualBytesWithoutPadding) - { - byte[] bigEndianBytes = input.ToUnsignedBigEndianBytes(); - actualBytesWithoutPadding = bigEndianBytes.Length; - bool isOddNumberOfBytes = bigEndianBytes.Length % 2 != 0; - if (isOddNumberOfBytes) - { - // make sure it's even - byte[] newBigEndianBytes = new byte[bigEndianBytes.Length + 1]; - - // Since it's big endian, we need to shift it right by a byte and fill MSB with zeroes. - Array.Copy(bigEndianBytes, 0, newBigEndianBytes, 1, bigEndianBytes.Length); - bigEndianBytes = newBigEndianBytes; - } - - byte[] result = new byte[bigEndianBytes.Length]; - - int ixResultByte = 0; - - for (int ixWord = bigEndianBytes.Length - 2; ixWord >= 0; ixWord -= 2) - { - for (int wordByteOffset = 0; wordByteOffset < 2; wordByteOffset++) - { - // need to flip individual bytes - result[ixResultByte++] = bigEndianBytes[ixWord + wordByteOffset]; - } - } - - bool hasExtraPaddingByte = bigEndianBytes.Length != actualBytesWithoutPadding; - - if (hasExtraPaddingByte) - { - result[bigEndianBytes.Length - 2] = result[bigEndianBytes.Length - 1]; - } - - return result; - } - - private static BigInteger GetBigIntegerFromLeastSignificantWordsFirstWith16BitMsbFirstWords(byte[] wordBytes, - int actualBytes) - { - bool hasBytePadding = actualBytes % 2 == 1; - if (hasBytePadding) - { - wordBytes[wordBytes.Length - 1] = wordBytes[wordBytes.Length - 2]; - wordBytes[wordBytes.Length - 2] = 0; - } - - byte[] bigEndianBytes = new byte[wordBytes.Length]; - - int ixResult = 0; - - for (int ixWord = wordBytes.Length - 2; ixWord >= 0; ixWord -= 2) - { - for (int ixByteInWord = 0; ixByteInWord < 2; ixByteInWord++) - { - bigEndianBytes[ixResult++] = wordBytes[ixWord + ixByteInWord]; - } - } - - var result = bigEndianBytes.ToBigIntegerFromBigEndianUnsignedBytes(); - return result; - } - - private static void EncipherBlock(UInt32[] v) - { - UInt32 sum = 0; - - for (int i = 0; i < InnerRounds; i++) - { - v[0] += (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ sum; - sum += Delta; - v[1] += (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ sum; - } - } - - private static void DecipherBlock(UInt32[] v) - { - UInt32 sum = DecodeInitialSum; - - for (int i = 0; i < InnerRounds; i++) - { - v[1] -= (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ sum; - sum -= Delta; - v[0] -= (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ sum; - } - } - - private static void EncodeSlice(byte[] data, int idx, int len, Action processBlock) - { - UInt32[] v = new UInt32[2]; - const int wordsPerBlock = 2; - - // Pack - for (int i = 0; i < wordsPerBlock; i++) - { - v[i] = ((UInt32)data[(idx + (4 * i)) % len]) << 24 | - ((UInt32)data[(idx + (4 * i) + 1) % len]) << 16 | - ((UInt32)data[(idx + (4 * i) + 2) % len]) << 8 | - ((UInt32)data[(idx + (4 * i) + 3) % len]); - } - - // Process - processBlock(v); - - // Unpack - for (int i = 0; i < wordsPerBlock; i++) - { - data[(idx + (4 * i) + 0) % len] = (byte)(v[i] >> 24); - data[(idx + (4 * i) + 1) % len] = (byte)((v[i] >> 16) & 0xff); - data[(idx + (4 * i) + 2) % len] = (byte)((v[i] >> 8) & 0xff); - data[(idx + (4 * i) + 3) % len] = (byte)(v[i] & 0xff); - } - } - } - - // Mimics ssss-split by only diffusing if 64 bits or larger - internal class SsssDiffuser : Diffuser - { - private static readonly XteaDiffuser _XteaDiffuser = new XteaDiffuser(); - private const int _ByteCutoff = 64 / 8; - - public override BigInteger Scramble(BigInteger input, int rawByteLength) - { - if (rawByteLength < _ByteCutoff) - { - return input; - } - - return _XteaDiffuser.Scramble(input, rawByteLength); - } - - public override BigInteger Unscramble(BigInteger input, int rawByteLength) - { - if (rawByteLength < _ByteCutoff) - { - return input; - } - - return _XteaDiffuser.Unscramble(input, rawByteLength); - } - } -} diff --git a/Miner/Cryptography/SecretSharing.cs b/Miner/Cryptography/SecretSharing.cs deleted file mode 100644 index 77562be3ef..0000000000 --- a/Miner/Cryptography/SecretSharing.cs +++ /dev/null @@ -1,58 +0,0 @@ -using AntShares.Algebra; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; - -namespace AntShares.Cryptography -{ - public static class SecretSharing - { - private static readonly Diffuser DefaultDiffuser = new SsssDiffuser(); - - public static byte[] Combine(IEnumerable points) - { - var allShares = points.ToArray(); - - if (allShares.Length == 0) - { - throw new ArgumentException("You must provide at least one secret share (piece).", nameof(points)); - } - - var secretCoefficient = LagrangeInterpolator.EvaluateAtZero(allShares); - var scrambledValue = secretCoefficient.PolynomialValue; - var unscrambledValue = DefaultDiffuser.Unscramble(scrambledValue, scrambledValue.ToByteArray().Length); - return unscrambledValue.ToUnsignedBigEndianBytes(); - } - - public static SplitSecret Split(byte[] secret, int threshold) - { - var irreduciblePolynomial = IrreduciblePolynomial.CreateOfByteSize(secret.Length); - var rawSecret = secret.ToBigIntegerFromBigEndianUnsignedBytes(); - var diffusedSecret = DefaultDiffuser.Scramble(rawSecret, secret.Length); - var secretCoefficient = new FiniteFieldPolynomial(irreduciblePolynomial, diffusedSecret); - - var allCoefficients = new[] { secretCoefficient } - .Concat( - GetRandomPolynomials( - irreduciblePolynomial, - threshold - 1) - ) - .ToArray(); - - return new SplitSecret(threshold, irreduciblePolynomial, allCoefficients); - } - - private static IEnumerable GetRandomPolynomials(IrreduciblePolynomial irreduciblePolynomial, int total) - { - var rng = RandomNumberGenerator.Create(); - - for (int i = 0; i < total; i++) - { - var randomCoefficientBytes = new byte[irreduciblePolynomial.SizeInBytes]; - rng.GetBytes(randomCoefficientBytes); - yield return new FiniteFieldPolynomial(irreduciblePolynomial, randomCoefficientBytes.ToBigIntegerFromLittleEndianUnsignedBytes()); - } - } - } -} diff --git a/Miner/Cryptography/SplitSecret.cs b/Miner/Cryptography/SplitSecret.cs deleted file mode 100644 index 00a1481b7d..0000000000 --- a/Miner/Cryptography/SplitSecret.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AntShares.Algebra; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; - -namespace AntShares.Cryptography -{ - public class SplitSecret - { - private readonly IrreduciblePolynomial _IrreduciblePolynomial; - private readonly FiniteFieldPolynomial[] _AllCoefficients; - - public int Threshold { get; private set; } - - public SplitSecret(int threshold, IrreduciblePolynomial irreduciblePolynomial, FiniteFieldPolynomial[] allCoefficients) - { - Threshold = threshold; - _IrreduciblePolynomial = irreduciblePolynomial; - _AllCoefficients = allCoefficients; - } - - public FiniteFieldPoint GetShare(int n) - { - var xPoly = new FiniteFieldPolynomial(_IrreduciblePolynomial, new BigInteger(n)); - var y = FiniteFieldPolynomial.EvaluateAt(n, _AllCoefficients); - return new FiniteFieldPoint(xPoly, y); - } - - public IEnumerable GetShares(int totalShares) - { - return Enumerable.Range(1, totalShares).Select(GetShare); - } - } -} diff --git a/Miner/Miner.csproj b/Miner/Miner.csproj deleted file mode 100644 index 4338ed7e92..0000000000 --- a/Miner/Miner.csproj +++ /dev/null @@ -1,112 +0,0 @@ - - - - - Debug - AnyCPU - {58870D2E-9DAE-41EF-9766-17C39238ED0F} - Exe - Properties - AntShares - Miner - v4.6.1 - 512 - true - - - - AntShares.Program - - - true - bin\Debug\ - TRACE;DEBUG - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - false - - - bin\Release\ - true - AnyCPU - false - prompt - MinimumRecommendedRules.ruleset - false - - - - - - - - - - - Network\RPC\RpcException.cs - - - Network\RPC\RpcServer.cs - - - Services\ConsoleServiceBase.cs - - - Services\ServiceProxy.cs - Component - - - Shell\MainService.cs - - - - - - - - - - - - - - - - - - - - - True - True - Settings.settings - - - - - - Designer - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - {bcd6b896-6cd0-4601-aa13-5672a15e0cad} - AntSharesCore - - - - - - \ No newline at end of file diff --git a/Miner/Program.cs b/Miner/Program.cs deleted file mode 100644 index 74bcb9ccb8..0000000000 --- a/Miner/Program.cs +++ /dev/null @@ -1,55 +0,0 @@ -using AntShares.Miner; -using System; -using System.IO; - -namespace AntShares -{ - static class Program - { - private static readonly object LogSync = new object(); - - private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) - { -#if DEBUG - Exception ex = (Exception)e.ExceptionObject; - using (FileStream fs = new FileStream("error.log", FileMode.Create, FileAccess.Write, FileShare.None)) - using (StreamWriter w = new StreamWriter(fs)) - { - w.WriteLine(ex.GetType()); - w.WriteLine(ex.Message); - w.WriteLine(ex.StackTrace); - AggregateException ex2 = ex as AggregateException; - if (ex2 != null) - { - foreach (Exception inner in ex2.InnerExceptions) - { - w.WriteLine(); - w.WriteLine(inner.Message); - w.WriteLine(inner.StackTrace); - } - } - } -#endif - } - - internal static void Log(string message) - { - DateTime now = DateTime.Now; - string line = $"[{now.TimeOfDay:hh\\:mm\\:ss}] {message}"; - Console.WriteLine(line); - lock (LogSync) - { - string path = Path.Combine(AppContext.BaseDirectory, "Logs"); - Directory.CreateDirectory(path); - path = Path.Combine(path, $"{now:yyyy-MM-dd}.log"); - File.AppendAllLines(path, new[] { line }); - } - } - - static void Main(string[] args) - { - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - new MinerService().Run(args); - } - } -} diff --git a/Miner/Properties/AssemblyInfo.cs b/Miner/Properties/AssemblyInfo.cs deleted file mode 100644 index 81d223f5de..0000000000 --- a/Miner/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// 有关程序集的常规信息通过以下 -// 特性集控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("AntShares")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("AntShares")] -[assembly: AssemblyCopyright("© AntShares Project 2015 Released under the MIT license")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 使此程序集中的类型 -// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, -// 则将该类型上的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("c0331ede-270e-484b-9c21-3f853cf99bb3")] - -// 程序集的版本信息由下面四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: -[assembly: AssemblyVersion("1.0.*")] -//[assembly: AssemblyVersion("1.0.0.0")] -//[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Miner/Properties/Settings.Designer.cs b/Miner/Properties/Settings.Designer.cs deleted file mode 100644 index 274e126535..0000000000 --- a/Miner/Properties/Settings.Designer.cs +++ /dev/null @@ -1,44 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace AntShares.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute(".\\Chain")] - public string DataDirectoryPath { - get { - return ((string)(this["DataDirectoryPath"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("10333")] - public ushort NodePort { - get { - return ((ushort)(this["NodePort"])); - } - } - } -} diff --git a/Miner/Properties/Settings.settings b/Miner/Properties/Settings.settings deleted file mode 100644 index 3e1b3fec4b..0000000000 --- a/Miner/Properties/Settings.settings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - .\Chain - - - 10333 - - - \ No newline at end of file