diff --git a/src/NeoSharp.Application/Client/ConsoleReader.cs b/src/NeoSharp.Application/Client/ConsoleReader.cs index d4ac5d00..e6fd9d5b 100644 --- a/src/NeoSharp.Application/Client/ConsoleReader.cs +++ b/src/NeoSharp.Application/Client/ConsoleReader.cs @@ -71,11 +71,11 @@ public void AppendInputs(params string[] inputs) /// /// Prompt label /// Reteurn Secure string password - public SecureString ReadPassword(bool promptLabel = true) + public SecureString ReadPassword(string promptLabel = "Password: ") { - if (promptLabel) + if (promptLabel != null) { - _consoleWriter.WriteLine("Password: "); + _consoleWriter.WriteLine(promptLabel, ConsoleOutputStyle.Information); } State = ConsoleReaderState.ReadingPassword; diff --git a/src/NeoSharp.Application/Client/IConsoleReader.cs b/src/NeoSharp.Application/Client/IConsoleReader.cs index cd7ab234..aeffae88 100644 --- a/src/NeoSharp.Application/Client/IConsoleReader.cs +++ b/src/NeoSharp.Application/Client/IConsoleReader.cs @@ -19,7 +19,7 @@ public interface IConsoleReader /// /// Prompt label /// Reteurn Secure string password - SecureString ReadPassword(bool promptLabel = true); + SecureString ReadPassword(string promptLabel = "Password: "); /// /// Read string from console /// diff --git a/src/NeoSharp.Application/Controllers/PromptBlockchainController.cs b/src/NeoSharp.Application/Controllers/PromptBlockchainController.cs index 74abc003..f8dc3424 100644 --- a/src/NeoSharp.Application/Controllers/PromptBlockchainController.cs +++ b/src/NeoSharp.Application/Controllers/PromptBlockchainController.cs @@ -5,6 +5,7 @@ using NeoSharp.Core.Blockchain; using NeoSharp.Core.Blockchain.Processing; using NeoSharp.Core.Extensions; +using NeoSharp.Core.Network; using NeoSharp.Core.Types; namespace NeoSharp.Application.Controllers @@ -16,6 +17,7 @@ public class PromptBlockchainController : IPromptController private readonly IBlockPool _blockPool; private readonly ITransactionPool _transactionPool; private readonly IBlockchain _blockchain; + private readonly IBlockchainContext _blockchainContext; private readonly IConsoleWriter _consoleWriter; private readonly IConsoleReader _consoleReader; @@ -25,13 +27,21 @@ public class PromptBlockchainController : IPromptController /// Constructor /// /// Blockchain + /// The block chain context class. /// Block pool /// Transaction Pool /// Console writter /// Console reader - public PromptBlockchainController(IBlockchain blockchain, IBlockPool blockPool, ITransactionPool transactionPool, IConsoleWriter consoleWriter, IConsoleReader consoleReader) + public PromptBlockchainController( + IBlockchain blockchain, + IBlockchainContext blockchainContext, + IBlockPool blockPool, + ITransactionPool transactionPool, + IConsoleWriter consoleWriter, + IConsoleReader consoleReader) { _blockchain = blockchain; + _blockchainContext = blockchainContext; _blockPool = blockPool; _transactionPool = transactionPool; _consoleReader = consoleReader; @@ -67,8 +77,8 @@ public void StateCommand() { var memStr = FormatState(_transactionPool.Size); var blockStr = FormatState(_blockPool.Size); - var headStr = FormatState(_blockchain.LastBlockHeader?.Index); - var blStr = FormatState(_blockchain.CurrentBlock?.Index); + var headStr = FormatState(this._blockchainContext.LastBlockHeader?.Index); + var blStr = FormatState(this._blockchainContext.CurrentBlock?.Index); var blIndex = FormatState(0); // TODO #398: Change me var numSpaces = new int[] { memStr.Length, blockStr.Length, blIndex.Length, headStr.Length, blStr.Length }.Max() + 1; @@ -85,8 +95,8 @@ public void StateCommand() _consoleWriter.WriteLine("Headers: " + headStr.PadLeft(numSpaces, ' ') + " "); - WriteStatePercent(" Blocks", blStr.PadLeft(numSpaces, ' '), _blockchain.CurrentBlock?.Index, _blockchain.LastBlockHeader?.Index); - WriteStatePercent(" Index", blIndex.PadLeft(numSpaces, ' '), 0, _blockchain.CurrentBlock?.Index); + WriteStatePercent(" Blocks", blStr.PadLeft(numSpaces, ' '), this._blockchainContext.CurrentBlock?.Index, this._blockchainContext.LastBlockHeader?.Index); + WriteStatePercent(" Index", blIndex.PadLeft(numSpaces, ' '), 0, this._blockchainContext.CurrentBlock?.Index); } /// diff --git a/src/NeoSharp.Application/Controllers/PromptWalletController.cs b/src/NeoSharp.Application/Controllers/PromptWalletController.cs index 29a1d65e..9402eefe 100644 --- a/src/NeoSharp.Application/Controllers/PromptWalletController.cs +++ b/src/NeoSharp.Application/Controllers/PromptWalletController.cs @@ -1,9 +1,11 @@ -using System.Linq; +using System; +using System.Linq; using NeoSharp.Application.Attributes; using NeoSharp.Application.Client; using NeoSharp.Core.Extensions; using NeoSharp.Core.Types; using NeoSharp.Core.Wallet; +using NeoSharp.Core.Wallet.Exceptions; using NeoSharp.Core.Wallet.Helpers; namespace NeoSharp.Application.Controllers @@ -34,24 +36,24 @@ public PromptWalletController(IWalletManager walletManager, IConsoleWriter conso _consoleWriter = consoleWriter; } - [PromptCommand("wallet create", Category = "Wallet", Help = "Create a new wallet")] - public void WalletCreateCommand(string fileName) - { - _walletManager.CreateWallet(fileName); - var secureString = _consoleReader.ReadPassword(); - _consoleWriter.WriteLine("\n", ConsoleOutputStyle.Information); //How these line breaks can be improved? - var confirmationString = _consoleReader.ReadPassword(); - if (secureString.ToByteArray().SequenceEqual(confirmationString.ToByteArray())) - { - var walletAccount = _walletManager.CreateAndAddAccount(secureString); - _consoleWriter.WriteLine("\nAddress: " + walletAccount.Address, ConsoleOutputStyle.Information); - _consoleWriter.WriteLine("Public Key: " + _walletManager.GetPublicKeyFromNep2(walletAccount.Key, secureString), ConsoleOutputStyle.Information); - } - else - { - _consoleWriter.WriteLine("\nPasswords don't match.", ConsoleOutputStyle.Information); - } - + [PromptCommand("wallet create", Category = "Wallet", Help = "Create a new wallet")] + public void WalletCreateCommand(string fileName) + { + var secureString = _consoleReader.ReadPassword(); + _consoleWriter.ApplyStyle(ConsoleOutputStyle.Prompt); + var confirmationString = _consoleReader.ReadPassword("\nConfirm your password:"); + if (secureString.ToByteArray().SequenceEqual(confirmationString.ToByteArray())) + { + _walletManager.CreateWallet(fileName); + var walletAccount = _walletManager.CreateAndAddAccount(secureString); + _consoleWriter.ApplyStyle(ConsoleOutputStyle.Prompt); + _consoleWriter.WriteLine("\nAddress: " + walletAccount.Address, ConsoleOutputStyle.Information); + _consoleWriter.WriteLine("Public Key: " + _walletManager.GetPublicKeyFromNep2(walletAccount.Key, secureString), ConsoleOutputStyle.Information); + } + else + { + _consoleWriter.WriteLine("\nPasswords don't match.", ConsoleOutputStyle.Information); + } } [PromptCommand("wallet open", Category = "Wallet", Help = "Open wallet")] @@ -97,19 +99,18 @@ public void WalletSaveCommand(string fileName) [PromptCommand("account create", Category = "Account", Help = "Create a new account")] public void AccountCreateCommand() { - var secureString = _consoleReader.ReadPassword(); - _consoleWriter.ApplyStyle(ConsoleOutputStyle.Prompt); - _consoleWriter.WriteLine("\nConfirm your password:", ConsoleOutputStyle.Information); - var confirmationString = _consoleReader.ReadPassword(); - if(secureString.ToByteArray().SequenceEqual(confirmationString.ToByteArray())) - { - var walletAccount = _walletManager.CreateAndAddAccount(secureString); - _consoleWriter.WriteLine("\nAddress: " + walletAccount.Address, ConsoleOutputStyle.Information); - _consoleWriter.WriteLine("Public Key: " + _walletManager.GetPublicKeyFromNep2(walletAccount.Key, secureString), ConsoleOutputStyle.Information); - } - else - { - _consoleWriter.WriteLine("Passwords don't match."); + var secureString = _consoleReader.ReadPassword("Wallet password:"); + try + { + _walletManager.CheckIfPasswordMatchesOpenWallet(secureString); + _consoleWriter.ApplyStyle(ConsoleOutputStyle.Prompt); + var walletAccount = _walletManager.CreateAndAddAccount(secureString); + _consoleWriter.WriteLine("\nAddress: " + walletAccount.Address, ConsoleOutputStyle.Information); + _consoleWriter.WriteLine("Public Key: " + _walletManager.GetPublicKeyFromNep2(walletAccount.Key, secureString), ConsoleOutputStyle.Information); + } + catch(AccountsPasswordMismatchException) + { + _consoleWriter.WriteLine("\nInvalid password."); } } @@ -121,18 +122,87 @@ public void AccountDeleteCommand(string address) _consoleWriter.WriteLine("Account deleted."); } + [PromptCommand("account export nep2", Category = "Account", Help = "Exports an account in nep-2 format")] + public void AccountExportNep2(string address) + { + var walletAccount = _walletManager.GetAccount(address.ToScriptHash()); + if (walletAccount != null) + { + try + { + var walletPassword = _consoleReader.ReadPassword(); + byte[] accountPrivateKey = _walletManager.DecryptNep2(walletAccount.Key, walletPassword); + var newKeyPassword = _consoleReader.ReadPassword("\nNew key password:"); + var newKeyPasswordConfirmation = _consoleReader.ReadPassword("\nConfirm your password:"); + if (newKeyPassword.ToByteArray().SequenceEqual(newKeyPasswordConfirmation.ToByteArray())) + { + string nep2Key = _walletManager.EncryptNep2(accountPrivateKey, newKeyPassword); + _consoleWriter.WriteLine("\nExported NEP-2 Key: " + nep2Key); + } + else + { + _consoleWriter.WriteLine("\nPasswords don't match."); + } + } + catch (AccountsPasswordMismatchException) + { + _consoleWriter.WriteLine("\nInvalid password."); + } + + } + else + { + _consoleWriter.WriteLine("\nAccount not found."); + } + + } + + [PromptCommand("account export wif", Category = "Account", Help = "Exports an account in nep-2 format")] + public void AccountExportWif(string address) + { + var walletAccount = _walletManager.GetAccount(address.ToScriptHash()); + if (walletAccount != null) + { + try + { + var walletPassword = _consoleReader.ReadPassword(); + byte[] accountPrivateKey = _walletManager.DecryptNep2(walletAccount.Key, walletPassword); + string wif = _walletManager.PrivateKeyToWif(accountPrivateKey); + _consoleWriter.WriteLine("\nExported wif: " + wif); + } + catch (AccountsPasswordMismatchException) + { + _consoleWriter.WriteLine("\nInvalid password."); + } + } + else + { + _consoleWriter.WriteLine("\nAccount not found."); + } + } + + [PromptCommand("account alias", Category = "Account", Help = "Adds a label to an account")] + public void AddAccountAlias(string address, string alias) + { + UInt160 accountScriptHash = address.ToScriptHash(); + if(_walletManager.Contains(accountScriptHash)) + { + _walletManager.UpdateAccountAlias(accountScriptHash, alias); + }else + { + _consoleWriter.WriteLine("\nAccount not found."); + } + } + + /* TODO #404: Implement additional wallet features - wallet delete_addr {addr} wallet delete_token {token_contract_hash} wallet alias {addr} {title} import multisig_addr {pubkey in wallet} {minimum # of signatures required} {signing pubkey 1} {signing pubkey 2}... import watch_addr {address} import token {token_contract_hash} - export wif {address} - export nep2 {address} - */ /* diff --git a/src/NeoSharp.Application/NeoSharp.Application.csproj b/src/NeoSharp.Application/NeoSharp.Application.csproj index 71034dc1..a037e785 100644 --- a/src/NeoSharp.Application/NeoSharp.Application.csproj +++ b/src/NeoSharp.Application/NeoSharp.Application.csproj @@ -15,6 +15,9 @@ + + Always + Always diff --git a/src/NeoSharp.Application/appsettings.json b/src/NeoSharp.Application/appsettings.json index 2c0108df..ef01c611 100644 --- a/src/NeoSharp.Application/appsettings.json +++ b/src/NeoSharp.Application/appsettings.json @@ -1,17 +1,10 @@ { "network": { - "magic": 7630401, + "magic": 1953787457, "port": 8000, "forceIPv6": false, "peerEndPoints": [ - "tcp://neo-privnet:20333", - "tcp://neo-privnet:20334", - "tcp://neo-privnet:20335", - "tcp://neo-privnet:20336", - "tcp://neo-privnet:30333", - "tcp://neo-privnet:30334", - "tcp://neo-privnet:30335", - "tcp://neo-privnet:30336" + "tcp://seed1.neo.org:20333" ], "acl": { "path": "network-acl.json", @@ -41,7 +34,7 @@ "persistence": { "provider": "RocksDb", "rocksDbProvider": { - "filePath": "localhost" + "filePath": "ChainTestnet" }, "redisDbBinaryProvider": { "connectionString": "localhost", @@ -52,4 +45,4 @@ "databaseId": "0" } } -} +} \ No newline at end of file diff --git a/src/NeoSharp.Application/appsettings.neo-privnet.json b/src/NeoSharp.Application/appsettings.neo-privnet.json new file mode 100644 index 00000000..2c0108df --- /dev/null +++ b/src/NeoSharp.Application/appsettings.neo-privnet.json @@ -0,0 +1,55 @@ +{ + "network": { + "magic": 7630401, + "port": 8000, + "forceIPv6": false, + "peerEndPoints": [ + "tcp://neo-privnet:20333", + "tcp://neo-privnet:20334", + "tcp://neo-privnet:20335", + "tcp://neo-privnet:20336", + "tcp://neo-privnet:30333", + "tcp://neo-privnet:30334", + "tcp://neo-privnet:30335", + "tcp://neo-privnet:30336" + ], + "acl": { + "path": "network-acl.json", + "type": "Blacklist" + }, + "standByValidators": [ + "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", + "02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", + "03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", + "02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", + "024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", + "02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", + "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70" + ] + }, + "rpc": { + "listenEndPoint": "127.0.0.1,10332", + "#ssl": { + "path": "./rpc-ssl.cert", + "password": "changeme" + }, + "acl": { + "path": "rpc-acl.json", + "type": "Blacklist" + } + }, + "persistence": { + "provider": "RocksDb", + "rocksDbProvider": { + "filePath": "localhost" + }, + "redisDbBinaryProvider": { + "connectionString": "localhost", + "databaseId": "0" + }, + "redisDbJsonProvider": { + "connectionString": "localhost", + "databaseId": "0" + } + } +} diff --git a/src/NeoSharp.Core/Blockchain/Blockchain.cs b/src/NeoSharp.Core/Blockchain/Blockchain.cs index bca6fa2e..79d93fba 100644 --- a/src/NeoSharp.Core/Blockchain/Blockchain.cs +++ b/src/NeoSharp.Core/Blockchain/Blockchain.cs @@ -6,6 +6,7 @@ using NeoSharp.Core.Blockchain.Processing; using NeoSharp.Core.Cryptography; using NeoSharp.Core.Models; +using NeoSharp.Core.Network; using NeoSharp.Core.Persistence; using NeoSharp.Core.Types; @@ -14,21 +15,13 @@ namespace NeoSharp.Core.Blockchain public class Blockchain : IBlockchain, IDisposable { #region Private fields - private readonly IRepository _repository; private readonly IBlockHeaderPersister _blockHeaderPersister; private readonly IBlockProcessor _blockProcessor; + private readonly IBlockchainContext _blockchainContext; + private int _initialized; private readonly List _validators = new List(); - - #endregion - - #region Public fields - - public Block CurrentBlock { get; private set; } - - public BlockHeader LastBlockHeader { get; private set; } - #endregion /// @@ -37,17 +30,20 @@ public class Blockchain : IBlockchain, IDisposable /// Repository /// Block Header Persister /// Block Processor + /// Block chain context class. public Blockchain( IRepository repository, IBlockHeaderPersister blockHeaderPersister, - IBlockProcessor blockProcessor) + IBlockProcessor blockProcessor, + IBlockchainContext blockchainContext) { _repository = repository ?? throw new ArgumentNullException(nameof(repository)); _blockHeaderPersister = blockHeaderPersister ?? throw new ArgumentNullException(nameof(blockHeaderPersister)); _blockProcessor = blockProcessor ?? throw new ArgumentNullException(nameof(blockProcessor)); + _blockchainContext = blockchainContext ?? throw new ArgumentNullException(nameof(blockchainContext)); ; - _blockHeaderPersister.OnBlockHeadersPersisted += (_, blockHeaders) => LastBlockHeader = blockHeaders.Last(); - _blockProcessor.OnBlockProcessed += (_, block) => CurrentBlock = block; + _blockHeaderPersister.OnBlockHeadersPersisted += (_, blockHeaders) => this._blockchainContext.LastBlockHeader = blockHeaders.Last(); + _blockProcessor.OnBlockProcessed += (_, block) => this._blockchainContext.CurrentBlock = block; } public async Task InitializeBlockchain() @@ -60,15 +56,15 @@ public async Task InitializeBlockchain() var blockHeight = await _repository.GetTotalBlockHeight(); var blockHeaderHeight = await _repository.GetTotalBlockHeaderHeight(); - CurrentBlock = await GetBlock(blockHeight); - LastBlockHeader = await GetBlockHeader(blockHeaderHeight); + this._blockchainContext.CurrentBlock = await GetBlock(blockHeight); + this._blockchainContext.LastBlockHeader = await GetBlockHeader(blockHeaderHeight); - _blockHeaderPersister.LastBlockHeader = LastBlockHeader; - _blockProcessor.Run(CurrentBlock); + this._blockHeaderPersister.LastBlockHeader = this._blockchainContext.LastBlockHeader; - if (CurrentBlock == null || LastBlockHeader == null) + this._blockProcessor.Run(this._blockchainContext.CurrentBlock); + if (this._blockchainContext.CurrentBlock == null || this._blockchainContext.LastBlockHeader == null) { - await _blockProcessor.AddBlock(Genesis.GenesisBlock); + await this._blockProcessor.AddBlock(Genesis.GenesisBlock); } } diff --git a/src/NeoSharp.Core/Blockchain/Genesis.cs b/src/NeoSharp.Core/Blockchain/Genesis.cs index 6b1d82f0..9c8bec27 100644 --- a/src/NeoSharp.Core/Blockchain/Genesis.cs +++ b/src/NeoSharp.Core/Blockchain/Genesis.cs @@ -53,7 +53,7 @@ static Genesis() }; var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var blockOperationsManager = new BlockOperationsManager( Crypto.Default, diff --git a/src/NeoSharp.Core/Blockchain/GenesisAssets.cs b/src/NeoSharp.Core/Blockchain/GenesisAssets.cs index 42602876..2a51d48d 100644 --- a/src/NeoSharp.Core/Blockchain/GenesisAssets.cs +++ b/src/NeoSharp.Core/Blockchain/GenesisAssets.cs @@ -42,7 +42,7 @@ static GenesisAssets() Witness = new Witness[0] }; - new TransactionOperationsManager(Crypto.Default, witnessOperationManager) + new TransactionSigner(Crypto.Default, witnessOperationManager) .Sign(GoverningTokenRegisterTransaction); // GAS Token is represented as a RegisterTransaction of type UtilityToken @@ -61,7 +61,7 @@ static GenesisAssets() Witness = new Witness[0] }; - new TransactionOperationsManager(Crypto.Default, witnessOperationManager) + new TransactionSigner(Crypto.Default, witnessOperationManager) .Sign(UtilityTokenRegisterTransaction); var builder = new ConfigurationBuilder() diff --git a/src/NeoSharp.Core/Blockchain/IBlockchain.cs b/src/NeoSharp.Core/Blockchain/IBlockchain.cs index 69ead463..51270a5f 100644 --- a/src/NeoSharp.Core/Blockchain/IBlockchain.cs +++ b/src/NeoSharp.Core/Blockchain/IBlockchain.cs @@ -17,15 +17,15 @@ public interface IBlockchain #region Blocks & BlockHeaders - /// - /// Current block - /// - Block CurrentBlock { get; } + ///// + ///// Current block + ///// + //Block CurrentBlock { get; } - /// - /// Last block header - /// - BlockHeader LastBlockHeader { get; } + ///// + ///// Last block header + ///// + //BlockHeader LastBlockHeader { get; } /// /// Return the corresponding block information according to the specified height diff --git a/src/NeoSharp.Core/Blockchain/Processing/BlockPersister.cs b/src/NeoSharp.Core/Blockchain/Processing/BlockPersister.cs index 19ebc056..6d1b8712 100644 --- a/src/NeoSharp.Core/Blockchain/Processing/BlockPersister.cs +++ b/src/NeoSharp.Core/Blockchain/Processing/BlockPersister.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using NeoSharp.Core.Logging; using NeoSharp.Core.Models; using NeoSharp.Core.Persistence; @@ -12,6 +13,7 @@ public class BlockPersister : IBlockPersister private readonly IBlockHeaderPersister _blockHeaderPersister; private readonly ITransactionPersister _transactionPersister; private readonly ITransactionPool _transactionPool; + private readonly ILogger _logger; #endregion #region Constructor @@ -19,12 +21,14 @@ public class BlockPersister : IBlockPersister IRepository repository, IBlockHeaderPersister blockHeaderPersister, ITransactionPersister transactionPersister, - ITransactionPool transactionPool) + ITransactionPool transactionPool, + ILogger logger) { this._repository = repository; this._blockHeaderPersister = blockHeaderPersister; this._transactionPersister = transactionPersister; this._transactionPool = transactionPool; + _logger = logger; } #endregion @@ -68,6 +72,7 @@ public async Task Persist(params BlockHeader[] blockHeaders) public async Task IsBlockPersisted(Block block) { + this._logger.LogDebug($"Verify if the {block.Hash} is already in the blockchain."); var blockHeader = await this._repository.GetBlockHeader(block.Hash); if (blockHeader?.Type == HeaderType.Extended) @@ -80,6 +85,7 @@ public async Task IsBlockPersisted(Block block) throw new InvalidOperationException($"The block \"{block.Hash.ToString(true)}\" has an invalid hash."); } + this._logger.LogDebug($"The block with the hash {block.Hash} is not int the blockchain."); return false; } #endregion diff --git a/src/NeoSharp.Core/Blockchain/Processing/BlockPool.cs b/src/NeoSharp.Core/Blockchain/Processing/BlockPool.cs index 14015fe5..782a7eab 100644 --- a/src/NeoSharp.Core/Blockchain/Processing/BlockPool.cs +++ b/src/NeoSharp.Core/Blockchain/Processing/BlockPool.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Linq; using NeoSharp.Core.Extensions; +using NeoSharp.Core.Logging; using NeoSharp.Core.Models; using NeoSharp.Core.Types; @@ -11,6 +12,7 @@ public class BlockPool : IBlockPool { private const int DefaultCapacity = 10_000; + private readonly ILogger _logger; private readonly ConcurrentDictionary _blockPool = new ConcurrentDictionary(); public int Size => _blockPool.Count; @@ -19,6 +21,11 @@ public class BlockPool : IBlockPool public event EventHandler OnAdded; + public BlockPool(ILogger logger) + { + _logger = logger; + } + public bool TryGet(uint height, out Block block) { return _blockPool.TryGetValue(height, out block); @@ -35,6 +42,7 @@ public void Add(Block block) throw new InvalidOperationException($"The block with height \"{block.Index}\" was already queued to be added."); } + this._logger.LogInformation($"BlockPool count: {this._blockPool.Count}"); OnAdded?.Invoke(this, block); PrioritizeBlocks(); diff --git a/src/NeoSharp.Core/Blockchain/Processing/BlockProcessor.cs b/src/NeoSharp.Core/Blockchain/Processing/BlockProcessor.cs index 62d2dcb9..e95cec07 100644 --- a/src/NeoSharp.Core/Blockchain/Processing/BlockProcessor.cs +++ b/src/NeoSharp.Core/Blockchain/Processing/BlockProcessor.cs @@ -2,8 +2,10 @@ using System.Threading; using System.Threading.Tasks; using NeoSharp.Core.Helpers; +using NeoSharp.Core.Messaging.Messages; using NeoSharp.Core.Models; using NeoSharp.Core.Models.OperationManger; +using NeoSharp.Core.Network; using NeoSharp.Core.Types; namespace NeoSharp.Core.Blockchain.Processing @@ -16,8 +18,9 @@ public class BlockProcessor : IBlockProcessor private readonly IAsyncDelayer _asyncDelayer; private readonly IBlockOperationsManager _blockOperationsManager; private readonly IBlockPersister _blockPersister; + private readonly IBlockchainContext _blockchainContext; + private readonly IBroadcaster _broadcaster; private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - private Block _currentBlock; public event EventHandler OnBlockProcessed; @@ -25,19 +28,23 @@ public class BlockProcessor : IBlockProcessor IBlockPool blockPool, IAsyncDelayer asyncDelayer, IBlockOperationsManager blockOperationsManager, - IBlockPersister blockPersister) + IBlockPersister blockPersister, + IBlockchainContext blockchainContext, + IBroadcaster broadcaster) { _blockPool = blockPool ?? throw new ArgumentNullException(nameof(blockPool)); _asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); - _blockOperationsManager = blockOperationsManager; - _blockPersister = blockPersister ?? throw new ArgumentNullException(nameof(_blockPersister)); + _blockOperationsManager = blockOperationsManager ?? throw new ArgumentNullException(nameof(blockOperationsManager)); + _blockPersister = blockPersister ?? throw new ArgumentNullException(nameof(blockPersister)); + _blockchainContext = blockchainContext ?? throw new ArgumentNullException(nameof(blockchainContext)); + _broadcaster = broadcaster ?? throw new ArgumentNullException(nameof(broadcaster)); } // TODO #384: We will read the current block from Blockchain // because the logic to get that too complicated public void Run(Block currentBlock) { - _currentBlock = currentBlock; + this._blockchainContext.CurrentBlock = currentBlock; var cancellationToken = _cancellationTokenSource.Token; @@ -45,7 +52,13 @@ public void Run(Block currentBlock) { while (!cancellationToken.IsCancellationRequested) { - var nextBlockHeight = _currentBlock?.Index + 1 ?? 0; + if (this._blockchainContext.IsPeerConnected && this._blockchainContext.NeedPeerSync && !this._blockchainContext.IsSyncing) + { + this._broadcaster.Broadcast(new GetBlocksMessage(this._blockchainContext.CurrentBlock.Hash)); + this._blockchainContext.IsSyncing = true; + } + + var nextBlockHeight = currentBlock?.Index + 1 ?? 0; if (!_blockPool.TryGet(nextBlockHeight, out var block)) { @@ -56,7 +69,7 @@ public void Run(Block currentBlock) await this._blockPersister.Persist(block); _blockPool.Remove(nextBlockHeight); - _currentBlock = block; + this._blockchainContext.CurrentBlock = block; OnBlockProcessed?.Invoke(this, block); diff --git a/src/NeoSharp.Core/Blockchain/Processing/ITransactionVerifier.cs b/src/NeoSharp.Core/Blockchain/Processing/ITransactionVerifier.cs index d60e0874..c4ced43d 100644 --- a/src/NeoSharp.Core/Blockchain/Processing/ITransactionVerifier.cs +++ b/src/NeoSharp.Core/Blockchain/Processing/ITransactionVerifier.cs @@ -6,6 +6,6 @@ namespace NeoSharp.Core.Blockchain.Processing { public interface ITransactionVerifier { - Task Verify(Transaction transaction, IReadOnlyCollection transactionPool); + bool Verify(Transaction transaction); } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Blockchain/Processing/TransactionPool.cs b/src/NeoSharp.Core/Blockchain/Processing/TransactionPool.cs index c748e144..69b3ffdd 100644 --- a/src/NeoSharp.Core/Blockchain/Processing/TransactionPool.cs +++ b/src/NeoSharp.Core/Blockchain/Processing/TransactionPool.cs @@ -11,7 +11,8 @@ namespace NeoSharp.Core.Blockchain.Processing { public class TransactionPool : ITransactionPool { - private readonly ITransactionOperationsManager _transactionOperationsManager; + private readonly ITransactionSigner _transactionSigner; + private readonly ITransactionVerifier _transactionVerifier; private class TimeStampedTransaction { @@ -55,9 +56,9 @@ public int Compare(TimeStampedTransaction a, TimeStampedTransaction b) private readonly ConcurrentDictionary _transactionPool = new ConcurrentDictionary(); private readonly IComparer _comparer; - public TransactionPool(ITransactionOperationsManager transactionOperationsManager, IComparer comparer = null) + public TransactionPool(ITransactionSigner transactionSigner, IComparer comparer = null) { - _transactionOperationsManager = transactionOperationsManager; + _transactionSigner = transactionSigner; _comparer = new TimeStampedTransactionComparer(comparer); } @@ -69,12 +70,20 @@ public void Add(Transaction transaction) { if (transaction == null) throw new ArgumentNullException(nameof(transaction)); - this._transactionOperationsManager.Sign(transaction); + this._transactionSigner.Sign(transaction); - if (!this._transactionOperationsManager.Verify(transaction)) + if (!this._transactionVerifier.Verify(transaction)) { throw new InvalidOperationException($"The transaction with hash \"{transaction.Hash}\" was not passed verification."); } + + if (this.Where(p => p != transaction) + .SelectMany(p => p.Inputs) + .Intersect(transaction.Inputs) + .Any()) + { + throw new InvalidOperationException($"The transaction with hash \"{transaction.Hash}\" was already queued to be added."); + } if (!_transactionPool.TryAdd(transaction.Hash, new TimeStampedTransaction(transaction))) { diff --git a/src/NeoSharp.Core/Blockchain/Processing/TransactionProcessor.cs b/src/NeoSharp.Core/Blockchain/Processing/TransactionProcessor.cs index 79f6b031..2c2a61e9 100644 --- a/src/NeoSharp.Core/Blockchain/Processing/TransactionProcessor.cs +++ b/src/NeoSharp.Core/Blockchain/Processing/TransactionProcessor.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using NeoSharp.Core.Helpers; using NeoSharp.Core.Models; +using NeoSharp.Core.Models.OperationManger; using NeoSharp.Core.Persistence; using NeoSharp.Core.Types; @@ -61,8 +62,17 @@ public void Run() continue; } - var valid = await _transactionVerifier.Verify(transaction, - transactionPool.Where(t => t.Hash != transactionHash).ToArray()); + var valid = _transactionVerifier.Verify(transaction); + + if (transactionPool + .Where(t => t.Hash != transactionHash) + .Where(p => p != transaction) + .SelectMany(p => p.Inputs) + .Intersect(transaction.Inputs) + .Any()) + { + valid = false; + } if (valid) { diff --git a/src/NeoSharp.Core/DI/IContainerBuilder.cs b/src/NeoSharp.Core/DI/IContainerBuilder.cs index a8c90fa8..f54ce9a4 100644 --- a/src/NeoSharp.Core/DI/IContainerBuilder.cs +++ b/src/NeoSharp.Core/DI/IContainerBuilder.cs @@ -44,6 +44,8 @@ void RegisterInstance(TService instance) void RegisterInstanceCreator(Func instanceCreator) where TService : class; + void RegisterCollectionOf(); + void RegisterModule() where TModule : class, IModule, new(); diff --git a/src/NeoSharp.Core/DI/Modules/BlockchainModule.cs b/src/NeoSharp.Core/DI/Modules/BlockchainModule.cs index efd6507d..9a07e412 100644 --- a/src/NeoSharp.Core/DI/Modules/BlockchainModule.cs +++ b/src/NeoSharp.Core/DI/Modules/BlockchainModule.cs @@ -4,6 +4,7 @@ using NeoSharp.Core.Blockchain.State; using NeoSharp.Core.Models; using NeoSharp.Core.Models.OperationManger; +using NeoSharp.Core.Types; namespace NeoSharp.Core.DI.Modules { @@ -21,6 +22,7 @@ public void Register(IContainerBuilder containerBuilder) containerBuilder.RegisterSingleton(); containerBuilder.RegisterSingleton, TransactionComparer>(); containerBuilder.RegisterSingleton(); + containerBuilder.RegisterSingleton(); containerBuilder.RegisterSingleton, TransactionPersister>(); containerBuilder.RegisterSingleton, ClaimTransactionPersister>(); @@ -32,7 +34,8 @@ public void Register(IContainerBuilder containerBuilder) containerBuilder.RegisterSingleton, EnrollmentTransactionPersister>(); containerBuilder.RegisterSingleton(); - containerBuilder.RegisterSingleton(); + containerBuilder.RegisterSingleton(); + containerBuilder.RegisterSingleton(); containerBuilder.RegisterSingleton(); containerBuilder.RegisterSingleton(); #endregion diff --git a/src/NeoSharp.Core/DI/Modules/NetworkModule.cs b/src/NeoSharp.Core/DI/Modules/NetworkModule.cs index d425ad4a..a1f64f22 100644 --- a/src/NeoSharp.Core/DI/Modules/NetworkModule.cs +++ b/src/NeoSharp.Core/DI/Modules/NetworkModule.cs @@ -1,8 +1,4 @@ -using System.Linq; -using NeoSharp.Core.Extensions; -using NeoSharp.Core.Logging; -using NeoSharp.Core.Messaging; -using NeoSharp.Core.Messaging.Handlers; +using NeoSharp.Core.Messaging; using NeoSharp.Core.Network; using NeoSharp.Core.Network.Protocols; using NeoSharp.Core.Network.Rpc; @@ -16,6 +12,7 @@ public class NetworkModule : IModule public void Register(IContainerBuilder containerBuilder) { containerBuilder.RegisterSingleton(); + containerBuilder.RegisterSingleton(); containerBuilder.RegisterSingleton(); containerBuilder.RegisterSingleton(); @@ -30,15 +27,8 @@ public void Register(IContainerBuilder containerBuilder) containerBuilder.RegisterSingleton(); containerBuilder.RegisterSingleton(); - var messageHandlerTypes = typeof(VersionMessageHandler).Assembly - .GetExportedTypes() - .Where(t => t.IsClass && !t.IsAbstract && t.IsAssignableToGenericType(typeof(IMessageHandler<>)) && - t != typeof(MessageHandlerProxy)) - .ToArray(); - - containerBuilder.Register(typeof(IMessageHandler<>), messageHandlerTypes); - containerBuilder.RegisterInstanceCreator>(c => - new MessageHandlerProxy(c, messageHandlerTypes, c.Resolve>())); + containerBuilder.RegisterCollectionOf(); + containerBuilder.RegisterSingleton(); } } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/AddrMessageMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/AddrMessageMessageHandler.cs index f998f866..2d890324 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/AddrMessageMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/AddrMessageMessageHandler.cs @@ -6,36 +6,45 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class AddrMessageMessageHandler : IMessageHandler + public class AddrMessageMessageHandler : MessageHandler { - #region Variables - + #region Private Fields private readonly IServer _server; - #endregion - /// - /// Constructor - /// - public AddrMessageMessageHandler(IServer server) + #region Constructor + //public AddrMessageMessageHandler(IServer server) + //{ + // _server = server ?? throw new ArgumentNullException(nameof(server)); + //} + public AddrMessageMessageHandler() { - _server = server ?? throw new ArgumentNullException(nameof(server)); } + #endregion - public Task Handle(AddrMessage message, IPeer sender) + #region MessageHandler override Methods + /// + public override Task Handle(AddrMessage message, IPeer sender) { - var connectedEndPoints = _server.ConnectedPeers - .Select(p => p.EndPoint) - .ToArray(); + //var connectedEndPoints = _server.ConnectedPeers + // .Select(p => p.EndPoint) + // .ToArray(); - var endPointsToConnect = message.Payload.Address - .Select(nat => new EndPoint(Protocol.Tcp, nat.EndPoint)) - .Where(ep => !connectedEndPoints.Contains(ep)) - .ToArray(); + //var endPointsToConnect = message.Payload.Address + // .Select(nat => new EndPoint(Protocol.Tcp, nat.EndPoint)) + // .Where(ep => !connectedEndPoints.Contains(ep)) + // .ToArray(); - _server.ConnectToPeers(endPointsToConnect); + //_server.ConnectToPeers(endPointsToConnect); return Task.CompletedTask; } + + /// + public override bool CanHandle(Message message) + { + return message is AddrMessage; + } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/BlockHeadersMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/BlockHeadersMessageHandler.cs index add831a6..8209e4ed 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/BlockHeadersMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/BlockHeadersMessageHandler.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using NeoSharp.Core.Blockchain; using NeoSharp.Core.Blockchain.Processing; using NeoSharp.Core.Logging; using NeoSharp.Core.Messaging.Messages; @@ -12,22 +11,31 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class BlockHeadersMessageHandler : IMessageHandler + public class BlockHeadersMessageHandler : MessageHandler { + #region Private Fields private const int MaxBlocksCountToSync = 500; private readonly IBlockPersister _blockPersister; - private readonly IBlockchain _blockchain; + private readonly IBlockchainContext _blockchainContext; private readonly ILogger _logger; + #endregion - public BlockHeadersMessageHandler(IBlockPersister blockPersister, IBlockchain blockchain, ILogger logger) + #region Constructor + public BlockHeadersMessageHandler( + IBlockPersister blockPersister, + IBlockchainContext blockchainContext, + ILogger logger) { _blockPersister = blockPersister ?? throw new ArgumentNullException(nameof(blockPersister)); - _blockchain = blockchain ?? throw new ArgumentNullException(nameof(blockchain)); + _blockchainContext = blockchainContext ?? throw new ArgumentNullException(nameof(blockchainContext)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + #endregion - public async Task Handle(BlockHeadersMessage message, IPeer sender) + #region MessageHandler override Methods + /// + public override async Task Handle(BlockHeadersMessage message, IPeer sender) { async void HeadersPersisted(object _, BlockHeader[] blockHeaders) => await BlockHeadersPersisted(sender, blockHeaders); @@ -42,16 +50,23 @@ public async Task Handle(BlockHeadersMessage message, IPeer sender) _blockPersister.OnBlockHeadersPersisted -= HeadersPersisted; } - if (_blockchain.LastBlockHeader.Index < sender.Version.CurrentBlockIndex) + if (this._blockchainContext.LastBlockHeader.Index < sender.Version.CurrentBlockIndex) { _logger.LogInformation( - $"The peer has {sender.Version.CurrentBlockIndex + 1} blocks but the current number of block headers is {_blockchain.LastBlockHeader.Index + 1}."); - await sender.Send(new GetBlockHeadersMessage(_blockchain.LastBlockHeader.Hash)); + $"The peer has {sender.Version.CurrentBlockIndex + 1} blocks but the current number of block headers is {this._blockchainContext.LastBlockHeader.Index + 1}."); + await sender.Send(new GetBlockHeadersMessage(this._blockchainContext.LastBlockHeader.Hash)); } } - #region Find a better place for block sync + /// + public override bool CanHandle(Message message) + { + return message is BlockHeadersMessage; + } + #endregion + #region Private Methods + // TODO #432: Find btter place for block sync private static async Task BlockHeadersPersisted(IPeer source, IEnumerable blockHeaders) { var blockHashes = blockHeaders diff --git a/src/NeoSharp.Core/Messaging/Handlers/BlockMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/BlockMessageHandler.cs index 78cd6c72..004c17b8 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/BlockMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/BlockMessageHandler.cs @@ -1,38 +1,67 @@ using System; using System.Threading.Tasks; using NeoSharp.Core.Blockchain.Processing; +using NeoSharp.Core.Logging; using NeoSharp.Core.Messaging.Messages; +using NeoSharp.Core.Models.OperationManger; using NeoSharp.Core.Network; namespace NeoSharp.Core.Messaging.Handlers { - public class BlockMessageHandler : IMessageHandler + public class BlockMessageHandler : MessageHandler { - #region Variables - + #region Private Fields private readonly IBlockProcessor _blockProcessor; + private readonly IBlockOperationsManager _blockOperationsManager; private readonly IBroadcaster _broadcaster; - + private readonly ILogger _logger; #endregion + #region Constructor + /// /// Constructor /// /// Block Pool + /// Block operations manager. /// Broadcaster - public BlockMessageHandler(IBlockProcessor blockProcessor, IBroadcaster broadcaster) + /// Logger + public BlockMessageHandler( + IBlockProcessor blockProcessor, + IBlockOperationsManager blockOperationsManager, + IBroadcaster broadcaster, + ILogger logger) { - _blockProcessor = blockProcessor ?? throw new ArgumentNullException(nameof(blockProcessor)); - _broadcaster = broadcaster ?? throw new ArgumentNullException(nameof(broadcaster)); + this._blockProcessor = blockProcessor ?? throw new ArgumentNullException(nameof(blockProcessor)); + this._blockOperationsManager = blockOperationsManager; + this._broadcaster = broadcaster ?? throw new ArgumentNullException(nameof(broadcaster)); + this._logger = logger; } + #endregion - public async Task Handle(BlockMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override bool CanHandle(Message message) + { + return message is BlockMessage; + } + + /// + public override async Task Handle(BlockMessage message, IPeer sender) { var block = message.Payload; - await _blockProcessor.AddBlock(block); + if (block.Hash == null) + { + this._blockOperationsManager.Sign(block); + } - _broadcaster.Broadcast(message, sender); + this._logger.LogInformation($"Adding block {block.Hash} to the BlockPool with Index {block.Index}."); + await this._blockProcessor.AddBlock(block); + + this._logger.LogInformation($"Broadcasting block {block.Hash} with Index {block.Index}."); + this._broadcaster.Broadcast(message, sender); } + #endregion } } diff --git a/src/NeoSharp.Core/Messaging/Handlers/ConsensusMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/ConsensusMessageHandler.cs index f23b2007..3bd976a1 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/ConsensusMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/ConsensusMessageHandler.cs @@ -1,36 +1,41 @@ using System; using System.Threading.Tasks; -using NeoSharp.Core.Logging; using NeoSharp.Core.Messaging.Messages; using NeoSharp.Core.Network; namespace NeoSharp.Core.Messaging.Handlers { - public class ConsensusMessageHandler : IMessageHandler + public class ConsensusMessageHandler : MessageHandler { - #region Variables - + #region Private fields private readonly IBroadcaster _broadcaster; - private readonly ILogger _logger; - #endregion + #region Constructor /// /// Constructor /// /// Broadcaster - /// Logger - public ConsensusMessageHandler(IBroadcaster broadcaster, ILogger logger) + public ConsensusMessageHandler(IBroadcaster broadcaster) { _broadcaster = broadcaster ?? throw new ArgumentNullException(nameof(broadcaster)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + #endregion - public Task Handle(ConsensusMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override bool CanHandle(Message message) + { + return message is ConsensusMessage; + } + + /// + public override Task Handle(ConsensusMessage message, IPeer sender) { _broadcaster.Broadcast(message, sender); return Task.CompletedTask; } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/FilterAddMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/FilterAddMessageHandler.cs index 2230ca48..6461228e 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/FilterAddMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/FilterAddMessageHandler.cs @@ -1,35 +1,13 @@ -using System; -using System.Threading.Tasks; -using NeoSharp.Core.Logging; +using System.Threading.Tasks; using NeoSharp.Core.Messaging.Messages; using NeoSharp.Core.Network; namespace NeoSharp.Core.Messaging.Handlers { - public class FilterAddMessageHandler : IMessageHandler + public class FilterAddMessageHandler : MessageHandler { - #region Variables - - private readonly ILogger _logger; - - #endregion - - /// - /// Constructor - /// - /// Logger - public FilterAddMessageHandler(ILogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } - - /// - /// Handle FilterAdd message - /// - /// Message - /// Sender - /// Task - public async Task Handle(FilterAddMessage message, IPeer sender) + /// + public override async Task Handle(FilterAddMessage message, IPeer sender) { if (sender.BloomFilter != null) { @@ -38,5 +16,11 @@ public async Task Handle(FilterAddMessage message, IPeer sender) await Task.CompletedTask; } + + /// + public override bool CanHandle(Message message) + { + return message is FilterAddMessage; + } } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/FilterClearMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/FilterClearMessageHandler.cs index c2daf4ad..8114d22a 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/FilterClearMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/FilterClearMessageHandler.cs @@ -1,39 +1,23 @@ -using System; -using System.Threading.Tasks; -using NeoSharp.Core.Logging; +using System.Threading.Tasks; using NeoSharp.Core.Messaging.Messages; using NeoSharp.Core.Network; namespace NeoSharp.Core.Messaging.Handlers { - public class FilterClearMessageHandler : IMessageHandler + public class FilterClearMessageHandler : MessageHandler { - #region Variables - - private readonly ILogger _logger; - - #endregion - - /// - /// Constructor - /// - /// Logger - public FilterClearMessageHandler(ILogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } - - /// - /// Handle GetMemPool message - /// - /// Message - /// Sender - /// Task - public async Task Handle(FilterClearMessage message, IPeer sender) + /// + public override async Task Handle(FilterClearMessage message, IPeer sender) { sender.BloomFilter = null; await Task.CompletedTask; } + + /// + public override bool CanHandle(Message message) + { + return message is FilterClearMessage; + } } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/FilterLoadMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/FilterLoadMessageHandler.cs index aac3c266..b322e6d2 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/FilterLoadMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/FilterLoadMessageHandler.cs @@ -1,36 +1,14 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; using NeoSharp.Core.Cryptography; -using NeoSharp.Core.Logging; using NeoSharp.Core.Messaging.Messages; using NeoSharp.Core.Network; namespace NeoSharp.Core.Messaging.Handlers { - public class FilterLoadMessageHandler : IMessageHandler + public class FilterLoadMessageHandler : MessageHandler { - #region Variables - - private readonly ILogger _logger; - - #endregion - - /// - /// Constructor - /// - /// Logger - public FilterLoadMessageHandler(ILogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } - - /// - /// Handle FilterLoad message - /// - /// Message - /// Sender - /// Task - public async Task Handle(FilterLoadMessage message, IPeer sender) + /// + public override async Task Handle(FilterLoadMessage message, IPeer sender) { var payload = message.Payload; @@ -42,5 +20,11 @@ public async Task Handle(FilterLoadMessage message, IPeer sender) await Task.CompletedTask; } + + /// + public override bool CanHandle(Message message) + { + return message is FilterLoadMessage; + } } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/GetAddrMessageMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/GetAddrMessageMessageHandler.cs index e34309dd..701973bd 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/GetAddrMessageMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/GetAddrMessageMessageHandler.cs @@ -6,30 +6,25 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class GetAddrMessageMessageHandler : IMessageHandler + public class GetAddrMessageMessageHandler : MessageHandler { - - #region Constants - - const int MaxCountToSend = 200; - - #endregion - - #region Variables + #region Private fields + private const int MaxCountToSend = 200; private readonly IServer _server; - #endregion - /// - /// Constructor - /// + #region Constructor public GetAddrMessageMessageHandler(IServer server) { + // TODO #433: Replace IServer with IServerContext _server = server ?? throw new ArgumentNullException(nameof(server)); } + #endregion - public async Task Handle(GetAddrMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override async Task Handle(GetAddrMessage message, IPeer sender) { var rand = new Random(Environment.TickCount); var peers = _server.ConnectedPeers @@ -52,5 +47,12 @@ await sender.Send new AddrMessage(networkAddressWithTimes) ); } + + /// + public override bool CanHandle(Message message) + { + return message is GetAddrMessage; + } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/GetBlockHeadersMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/GetBlockHeadersMessageHandler.cs index 6ec0e17b..58b80aa3 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/GetBlockHeadersMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/GetBlockHeadersMessageHandler.cs @@ -10,17 +10,26 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class GetBlockHeadersMessageHandler : IMessageHandler + public class GetBlockHeadersMessageHandler : MessageHandler { + #region Private Fields private const int MaxBlockHeadersCountToReturn = 2000; private readonly IBlockchain _blockchain; + private Task GetBlockHeader(UInt256 hash) => _blockchain.GetBlockHeader(hash); + #endregion + + #region Constructor public GetBlockHeadersMessageHandler(IBlockchain blockchain) { + // TODO #434: Remove Blockchain dependency from GetBlockHeadersMessageHandler and GetBlocksMessageHandler _blockchain = blockchain ?? throw new ArgumentNullException(nameof(blockchain)); } + #endregion - public async Task Handle(GetBlockHeadersMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override async Task Handle(GetBlockHeadersMessage message, IPeer sender) { var hashStart = (message.Payload.HashStart ?? new UInt256[0]) .Where(h => h != null) @@ -55,6 +64,11 @@ public async Task Handle(GetBlockHeadersMessage message, IPeer sender) await sender.Send(new BlockHeadersMessage(blockHeaders)); } - private Task GetBlockHeader(UInt256 hash) => _blockchain.GetBlockHeader(hash); + /// + public override bool CanHandle(Message message) + { + return message is GetBlockHeadersMessage; + } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/GetBlocksMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/GetBlocksMessageHandler.cs index ed03a59a..2c7fa690 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/GetBlocksMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/GetBlocksMessageHandler.cs @@ -10,17 +10,32 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class GetBlocksMessageHandler : IMessageHandler + public class GetBlocksMessageHandler : MessageHandler { + #region Private Fields private const int MaxBlocksCountToReturn = 500; private readonly IBlockchain _blockchain; + private Task GetBlockHeader(UInt256 hash) => _blockchain.GetBlockHeader(hash); + #endregion + + #region Constructor public GetBlocksMessageHandler(IBlockchain blockchain) { + // TODO #434: Remove Blockchain dependency from GetBlockHeadersMessageHandler and GetBlocksMessageHandler _blockchain = blockchain ?? throw new ArgumentNullException(nameof(blockchain)); } + #endregion - public async Task Handle(GetBlocksMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override bool CanHandle(Message message) + { + return message is GetBlocksMessage; + } + + /// + public override async Task Handle(GetBlocksMessage message, IPeer sender) { var hashStart = (message.Payload.HashStart ?? new UInt256[0]) .Where(h => h != null) @@ -54,7 +69,6 @@ public async Task Handle(GetBlocksMessage message, IPeer sender) await sender.Send(new InventoryMessage(InventoryType.Block, blockHashes)); } - - private Task GetBlockHeader(UInt256 hash) => _blockchain.GetBlockHeader(hash); + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/GetDataMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/GetDataMessageHandler.cs index bc55804a..abb0f286 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/GetDataMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/GetDataMessageHandler.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using NeoSharp.Core.Blockchain; using NeoSharp.Core.Cryptography; -using NeoSharp.Core.Extensions; using NeoSharp.Core.Logging; using NeoSharp.Core.Messaging.Messages; using NeoSharp.Core.Models; @@ -14,15 +13,14 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class GetDataMessageHandler : IMessageHandler + public class GetDataMessageHandler : MessageHandler { - #region Variables - + #region Private fields private readonly IBlockchain _blockchain; private readonly ILogger _logger; - #endregion + #region Constructor /// /// Constructor /// @@ -30,17 +28,16 @@ public class GetDataMessageHandler : IMessageHandler /// Logger public GetDataMessageHandler(IBlockchain blockchain, ILogger logger) { + // TODO #434: Title not aligned but the context is the same. + _blockchain = blockchain ?? throw new ArgumentNullException(nameof(blockchain)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + #endregion - /// - /// Handle GetData message - /// - /// Message - /// sender Peer - /// Task - public async Task Handle(GetDataMessage message, IPeer sender) + #region IMessageHandler orveride Methods + /// + public override async Task Handle(GetDataMessage message, IPeer sender) { var hashes = message.Payload.Hashes .Distinct() @@ -78,6 +75,14 @@ public async Task Handle(GetDataMessage message, IPeer sender) } } + /// + public override bool CanHandle(Message message) + { + return message is GetDataMessage; + } + #endregion + + #region Private Methods private async Task SendTransactions(IReadOnlyCollection transactionHashes, IPeer peer) { var transactions = await _blockchain.GetTransactions(transactionHashes); @@ -89,7 +94,7 @@ private async Task SendTransactions(IReadOnlyCollection transactionHash private async Task SendBlocks(IReadOnlyCollection blockHashes, IPeer peer) { - var blocks = await _blockchain.GetBlocks(blockHashes); + var blocks = (await _blockchain.GetBlocks(blockHashes)).ToList(); if (!blocks.Any()) return; @@ -117,11 +122,12 @@ private async Task SendBlocks(IReadOnlyCollection blockHashes, IPeer pe } } - private bool TestFilter(BloomFilter filter, Transaction tx) + private static bool TestFilter(BloomFilter filter, Transaction tx) { // TODO #380: encapsulate this in filter return false; } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/InventoryMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/InventoryMessageHandler.cs index d6c289b3..d67be90e 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/InventoryMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/InventoryMessageHandler.cs @@ -7,14 +7,13 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class InventoryMessageHandler : IMessageHandler + public class InventoryMessageHandler : MessageHandler { - #region Variables - + #region Private Fields private readonly ILogger _logger; - #endregion + #region Constructor /// /// Constructor /// @@ -23,14 +22,17 @@ public InventoryMessageHandler(ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + #endregion - /// - /// Handle Inventory message - /// - /// Message - /// Sender - /// Task - public Task Handle(InventoryMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override bool CanHandle(Message message) + { + return message is InventoryMessage; + } + + /// + public override Task Handle(InventoryMessage message, IPeer sender) { var inventoryType = message.Payload.Type; if (Enum.IsDefined(typeof(InventoryType), inventoryType) == false) @@ -53,7 +55,9 @@ public Task Handle(InventoryMessage message, IPeer sender) return Task.CompletedTask; } + return sender.Send(new GetDataMessage(inventoryType, hashes)); } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/MemPoolMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/MemPoolMessageHandler.cs index 9878f6e2..b5728ec9 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/MemPoolMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/MemPoolMessageHandler.cs @@ -8,14 +8,13 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class MemPoolMessageHandler : IMessageHandler + public class MemPoolMessageHandler : MessageHandler { - #region Variables - + #region Private fields private readonly ITransactionPool _transactionPool; - #endregion + #region Constructor /// /// Constructor /// @@ -24,14 +23,11 @@ public MemPoolMessageHandler(ITransactionPool transactionPool) { _transactionPool = transactionPool ?? throw new ArgumentNullException(nameof(transactionPool)); } + #endregion - /// - /// Handle GetMemPool message - /// - /// Message - /// Sender - /// Task - public async Task Handle(MemPoolMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override async Task Handle(MemPoolMessage message, IPeer sender) { var hashes = _transactionPool .Take(InventoryPayload.MaxHashes) @@ -40,5 +36,12 @@ public async Task Handle(MemPoolMessage message, IPeer sender) await sender.Send(new InventoryMessage(InventoryType.Transaction, hashes)); } + + /// + public override bool CanHandle(Message message) + { + return message is MemPoolMessage; + } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/TransactionMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/TransactionMessageHandler.cs index d4804d60..4b0296fc 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/TransactionMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/TransactionMessageHandler.cs @@ -10,49 +10,60 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class TransactionMessageHandler : IMessageHandler + public class TransactionMessageHandler : MessageHandler { - #region Variables - + #region Private Fields private readonly IBlockchain _blockchain; private readonly ITransactionPool _transactionPool; - private readonly ITransactionOperationsManager _transactionOperationsManager; + private readonly ITransactionSigner _transactionSigner; private readonly ILogger _logger; - #endregion + #region Constructor /// /// Constructor /// /// Blockchain /// Transaction Pool - /// The transaction operation manager + /// The transaction operation manager /// Logger public TransactionMessageHandler( IBlockchain blockchain, ITransactionPool transactionPool, - ITransactionOperationsManager transactionOperationsManager, + ITransactionSigner transactionSigner, ILogger logger) { _blockchain = blockchain ?? throw new ArgumentNullException(nameof(blockchain)); _transactionPool = transactionPool ?? throw new ArgumentNullException(nameof(transactionPool)); - _transactionOperationsManager = transactionOperationsManager; + _transactionSigner = transactionSigner; _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + #endregion + + #region MessageHandler override methods + /// + public override bool CanHandle(Message message) + { + return message is TransactionMessage; + } - public async Task Handle(TransactionMessage message, IPeer sender) + /// + public override async Task Handle(TransactionMessage message, IPeer sender) { var transaction = message.Payload; if (transaction is MinerTransaction) return; // TODO #373: check if the hash of the transaction is known already - + if (transaction.Hash == null) + { + this._transactionSigner.Sign(transaction); + } var transactionExists = await _blockchain.ContainsTransaction(transaction.Hash); if (transactionExists) { - _logger.LogInformation($"The transaction \"{transaction.Hash.ToString(true)}\" exists already on the blockchain."); + _logger.LogInformation($"The transaction \"{transaction.Hash?.ToString(true)}\" exists already on the blockchain."); return; } @@ -62,14 +73,8 @@ public async Task Handle(TransactionMessage message, IPeer sender) // TODO #374: It is a bit more complicated _transactionPool.Add(transaction); - - var transactionAdded = true; - - if (!transactionAdded) - { - _logger.LogWarning($"The transaction \"{transaction.Hash.ToString(true)}\" was not added to the blockchain."); - return; - } + _logger.LogInformation($"Transaction with Hash {transaction.Hash?.ToString(true)} added to the TransactionPool."); } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/VerAckMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/VerAckMessageHandler.cs index d6857f1f..c0d6e51a 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/VerAckMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/VerAckMessageHandler.cs @@ -1,33 +1,48 @@ using System; using System.Threading.Tasks; -using NeoSharp.Core.Blockchain; using NeoSharp.Core.Logging; using NeoSharp.Core.Messaging.Messages; using NeoSharp.Core.Network; namespace NeoSharp.Core.Messaging.Handlers { - public class VerAckMessageHandler : IMessageHandler + public class VerAckMessageHandler : MessageHandler { - private readonly IBlockchain _blockchain; + #region Private Fields + private readonly IBlockchainContext _blockchainContext; private readonly ILogger _logger; + #endregion - public VerAckMessageHandler(IBlockchain blockchain, ILogger logger) + #region Constructor + public VerAckMessageHandler( + IBlockchainContext blockchainContext, + ILogger logger) { - _blockchain = blockchain ?? throw new ArgumentNullException(nameof(blockchain)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + this._blockchainContext = blockchainContext ?? throw new ArgumentNullException(nameof(blockchainContext)); + this._logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + #endregion - public async Task Handle(VerAckMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override bool CanHandle(Message message) + { + return message is VerAckMessage; + } + + /// + public override async Task Handle(VerAckMessage message, IPeer sender) { sender.IsReady = true; + this._blockchainContext.SetPeerCurrentBlockIndex(sender.Version.CurrentBlockIndex); - if (_blockchain.LastBlockHeader.Index < sender.Version.CurrentBlockIndex) + if (this._blockchainContext.NeedPeerSync) { - _logger.LogInformation($"The peer has {sender.Version.CurrentBlockIndex + 1} blocks but the current number of block headers is {_blockchain.LastBlockHeader.Index + 1}."); + this._logger.LogInformation($"The peer has {sender.Version.CurrentBlockIndex + 1} blocks but the current number of block headers is {_blockchainContext.LastBlockHeader.Index + 1}."); - await sender.Send(new GetBlockHeadersMessage(_blockchain.LastBlockHeader.Hash)); + await sender.Send(new GetBlockHeadersMessage(_blockchainContext.LastBlockHeader.Hash)); } } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Handlers/VersionMessageHandler.cs b/src/NeoSharp.Core/Messaging/Handlers/VersionMessageHandler.cs index 721b82b1..177b02ee 100644 --- a/src/NeoSharp.Core/Messaging/Handlers/VersionMessageHandler.cs +++ b/src/NeoSharp.Core/Messaging/Handlers/VersionMessageHandler.cs @@ -6,15 +6,14 @@ namespace NeoSharp.Core.Messaging.Handlers { - public class VersionMessageHandler : IMessageHandler + public class VersionMessageHandler : MessageHandler { - #region Variables - + #region Private Fields private readonly ILogger _logger; private readonly IServerContext _serverContext; - #endregion + #region Constructor /// /// Constructor /// @@ -25,32 +24,33 @@ public VersionMessageHandler(IServerContext serverContext, ILogger - /// Handle message - /// - /// Message - /// Sender - /// Task - public async Task Handle(VersionMessage message, IPeer sender) + #region MessageHandler override methods + /// + public override async Task Handle(VersionMessage message, IPeer sender) { sender.Version = message.Payload; - if (_serverContext.Version.Nonce == sender.Version.Nonce) { throw new InvalidOperationException($"The handshake is failed due to \"{nameof(_serverContext.Version.Nonce)}\" value equality."); } // Change protocol? - if (sender.ChangeProtocol(message.Payload)) { _logger?.LogWarning("Changed protocol."); } // Send Ack - await sender.Send(); } + + /// + public override bool CanHandle(Message message) + { + return message is VersionMessage; + } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/IMessageHandlerProxy.cs b/src/NeoSharp.Core/Messaging/IMessageHandlerProxy.cs new file mode 100644 index 00000000..366adba1 --- /dev/null +++ b/src/NeoSharp.Core/Messaging/IMessageHandlerProxy.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using NeoSharp.Core.Network; + +namespace NeoSharp.Core.Messaging +{ + public interface IMessageHandlerProxy + { + Task Handle(Message message, IPeer sender); + } +} \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/IMessageHandler[TMessage].cs b/src/NeoSharp.Core/Messaging/IMessageHandler[TMessage].cs index 856820b2..44b13c05 100644 --- a/src/NeoSharp.Core/Messaging/IMessageHandler[TMessage].cs +++ b/src/NeoSharp.Core/Messaging/IMessageHandler[TMessage].cs @@ -3,8 +3,16 @@ namespace NeoSharp.Core.Messaging { - public interface IMessageHandler where TMessage : Message + public abstract class MessageHandler : IMessageHandler + where TMessage : Message { - Task Handle(TMessage message, IPeer sender); + public abstract bool CanHandle(Message message); + + public abstract Task Handle(TMessage message, IPeer sender); + } + + public interface IMessageHandler + { + bool CanHandle(Message message); } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/MessageHandlerProxy.cs b/src/NeoSharp.Core/Messaging/MessageHandlerProxy.cs index b8022dbf..dd558ca0 100644 --- a/src/NeoSharp.Core/Messaging/MessageHandlerProxy.cs +++ b/src/NeoSharp.Core/Messaging/MessageHandlerProxy.cs @@ -1,153 +1,58 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; -using NeoSharp.Core.DI; using NeoSharp.Core.Logging; using NeoSharp.Core.Network; namespace NeoSharp.Core.Messaging { - public class MessageHandlerProxy : IMessageHandler + public class MessageHandlerProxy : IMessageHandlerProxy { - #region Variables - - private readonly IContainer _container; + #region Private fields + private readonly IEnumerable _messageHandlers; private readonly ILogger _logger; - private readonly IReadOnlyDictionary _messageHandlerInvokers; + //private readonly Dictionary _handlers; #endregion - /// - /// Constructor - /// - /// Container - /// MessageHandler types - /// Logger - public MessageHandlerProxy(IContainer container, IEnumerable messageHandlerTypes, ILogger logger) + #region Constructor + public MessageHandlerProxy( + IEnumerable messageHandlers, + ILogger logger) { - _container = container; + _messageHandlers = messageHandlers; _logger = logger; - _messageHandlerInvokers = messageHandlerTypes - .Select(CreateMessageHandlerInvoker) - .ToDictionary(x => x.MessageType, x => x.MessageHandlerInvoker); } + #endregion - /// - /// Handle message - /// - /// Message - /// Sender - /// Task - public Task Handle(Message message, IPeer sender) + #region MessageHandler implementation + public async Task Handle(Message message, IPeer sender) { if (message == null) throw new ArgumentNullException(nameof(message)); - var messageType = message.GetType(); - var messageHandler = ResolveMessageHandler(messageType); - var messageHandlerName = messageHandler.GetType().Name; - var startedAt = LogMessageHandlingStart(messageHandlerName); - var messageHandlerInvoker = GetMessageHandlerInvoker(messageType); - var handleMessageTask = (Task)messageHandlerInvoker.DynamicInvoke(messageHandler, message, sender); - - return handleMessageTask.ContinueWith(t => - { - if (t.IsCompletedSuccessfully) - { - LogMessageHandlingEnd(startedAt, messageHandlerName); - return; - } - - if (t.IsFaulted) - { - LogMessageHandlingEnd(startedAt, messageHandlerName, handleMessageTask.Exception); - return; - } - }); - } - - private static (Type MessageType, Delegate MessageHandlerInvoker) CreateMessageHandlerInvoker(Type messageHandlerType) - { - const string handleMethodName = nameof(IMessageHandler.Handle); - const BindingFlags bindingFlags = BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public; - - var handleMethodInfo = messageHandlerType.GetMethod(handleMethodName, bindingFlags); - var messageType = handleMethodInfo.GetParameters().First().ParameterType; - var messageHandlerInvoker = Delegate.CreateDelegate( - Expression.GetFuncType(messageHandlerType, messageType, typeof(IPeer), typeof(Task)), - null, - handleMethodInfo); - - return (messageType, messageHandlerInvoker); - } + var messageHandler = this._messageHandlers.SingleOrDefault(x => x.CanHandle(message)); - private object ResolveMessageHandler(Type messageType) - { - var messageHandler = _container.Resolve(typeof(IMessageHandler<>).MakeGenericType(messageType)); if (messageHandler == null) { - throw new InvalidOperationException( - $"The message of \"{messageType}\" type has no registered handlers."); + this._logger.LogError($"could not find the handler for the message type {message.GetType()}"); + return; } - return messageHandler; - } + var startedAt = DateTime.UtcNow; + _logger.LogDebug($"The message handler \"{messageHandler.GetType().Name}\" started message handling at {startedAt:yyyy-MM-dd HH:mm:ss}."); - private Delegate GetMessageHandlerInvoker(Type messageType) - { - if (_messageHandlerInvokers.TryGetValue(messageType, out var messageHandlerInvoker) == false) - { - throw new InvalidOperationException( - $"The message of \"{messageType}\" type has no registered handlers."); - } + dynamic specificMessageHandler = Convert.ChangeType(messageHandler, messageHandler.GetType()); + dynamic specificMessage = Convert.ChangeType(message, message.GetType()); + await specificMessageHandler.Handle(specificMessage, sender); + var completedAt = DateTime.UtcNow; - return messageHandlerInvoker; - } - - /// - /// Log start - /// - /// Message handler name - /// Return start date - private DateTime LogMessageHandlingStart(string messageHandlerName) - { - var startedAt = DateTime.Now; - - _logger.LogDebug( - $"The message handler \"{messageHandlerName}\" started message handling at {startedAt:yyyy-MM-dd HH:mm:ss}."); - - return startedAt; - } - - /// - /// Log end with error - /// - /// Start date - /// Message handler name - /// Error - private void LogMessageHandlingEnd(DateTime startedAt, string messageHandlerName, Exception error) - { - var completedAt = DateTime.Now; - var handledWithin = (completedAt - startedAt).TotalMilliseconds; - - _logger.LogError(error, - $"The message handler \"{messageHandlerName}\" faulted message handling at {completedAt:yyyy-MM-dd HH:mm:ss} ({handledWithin} ms)."); - } - - /// - /// Log end - /// - /// Start date - /// Message handler name - private void LogMessageHandlingEnd(DateTime startedAt, string messageHandlerName) - { - var completedAt = DateTime.Now; var handledWithin = (completedAt - startedAt).TotalMilliseconds; _logger.LogDebug( - $"The message handler \"{messageHandlerName}\" completed message handling at {completedAt:yyyy-MM-dd HH:mm:ss} ({handledWithin} ms)."); + $"The message handler \"{messageHandler.GetType().Name}\" completed message handling at {completedAt:yyyy-MM-dd HH:mm:ss} ({handledWithin} ms)."); } + #endregion } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Messaging/Messages/GetBlocksMessage.cs b/src/NeoSharp.Core/Messaging/Messages/GetBlocksMessage.cs index 2d374cae..881da8b9 100644 --- a/src/NeoSharp.Core/Messaging/Messages/GetBlocksMessage.cs +++ b/src/NeoSharp.Core/Messaging/Messages/GetBlocksMessage.cs @@ -1,4 +1,5 @@ -using NeoSharp.BinarySerialization; +using System.IO; +using NeoSharp.BinarySerialization; using NeoSharp.Core.Types; namespace NeoSharp.Core.Messaging.Messages @@ -24,7 +25,7 @@ public GetBlocksMessage(UInt256 hashStart) } } - public class GetBlocksPayload + public class GetBlocksPayload : ISerializable { // TODO #372: Why is it an array if it is always initialized with a single value? [BinaryProperty(0)] @@ -32,5 +33,17 @@ public class GetBlocksPayload [BinaryProperty(1)] public UInt256 HashStop = UInt256.Zero; + + public int Size { get; } + public void Serialize(BinaryWriter writer) + { + //writer.Write(this.HashStart); + //writer.Write(this.HashStop); + } + + public void Deserialize(BinaryReader reader) + { + throw new System.NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/BlockBase.cs b/src/NeoSharp.Core/Models/BlockBase.cs index 9510c74e..0e4dc2ce 100644 --- a/src/NeoSharp.Core/Models/BlockBase.cs +++ b/src/NeoSharp.Core/Models/BlockBase.cs @@ -37,22 +37,5 @@ public abstract class BlockBase [JsonProperty("hash")] public UInt256 Hash { get; private set; } #endregion - - #region Protected Methods - protected void Sign(BlockBase blockBase, byte[] signingSettings) - { - this.Version = blockBase.Version; - this.PreviousBlockHash = blockBase.PreviousBlockHash; - this.Timestamp = blockBase.Timestamp; - this.Index = blockBase.Index; - this.ConsensusData = blockBase.ConsensusData; - this.NextConsensus = blockBase.NextConsensus; - this.Type = blockBase.Type; - - this.Hash = new UInt256(Crypto.Default.Hash256(signingSettings)); - - } - #endregion - } } diff --git a/src/NeoSharp.Core/Models/ClaimTransaction.cs b/src/NeoSharp.Core/Models/ClaimTransaction.cs index dbd1106a..2fb4e361 100644 --- a/src/NeoSharp.Core/Models/ClaimTransaction.cs +++ b/src/NeoSharp.Core/Models/ClaimTransaction.cs @@ -1,5 +1,4 @@ -using System; -using System.IO; +using System.IO; using NeoSharp.BinarySerialization; using NeoSharp.Core.Converters; @@ -30,13 +29,5 @@ protected override int SerializeExclusiveData(IBinarySerializer serializer, Bina } #endregion - - //public override bool Verify() - //{ - // if (Version != 0) throw new ArgumentException(nameof(Version)); - // if (Claims == null || Claims.Length == 0) throw new ArgumentException(nameof(Claims)); - - // return base.Verify(); - //} } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/ContractTransaction.cs b/src/NeoSharp.Core/Models/ContractTransaction.cs index f27a3f63..2a8aefe6 100644 --- a/src/NeoSharp.Core/Models/ContractTransaction.cs +++ b/src/NeoSharp.Core/Models/ContractTransaction.cs @@ -8,13 +8,5 @@ public class ContractTransaction : Transaction { /// public ContractTransaction() : base(TransactionType.ContractTransaction) { } - - - //public override bool Verify() - //{ - // if (Version != 0x00) return false; - - // return base.Verify(); - //} } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/InvocationTransaction.cs b/src/NeoSharp.Core/Models/InvocationTransaction.cs index 26f4a089..972e3808 100644 --- a/src/NeoSharp.Core/Models/InvocationTransaction.cs +++ b/src/NeoSharp.Core/Models/InvocationTransaction.cs @@ -70,12 +70,5 @@ protected override int SerializeExclusiveData(IBinarySerializer serializer, Bina } #endregion - - //public override bool Verify() - //{ - // if (Gas.Value % 100000000 != 0) return false; - - // return base.Verify(); - //} } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/IssueTransaction.cs b/src/NeoSharp.Core/Models/IssueTransaction.cs index 5cc009f4..b55e5c7b 100644 --- a/src/NeoSharp.Core/Models/IssueTransaction.cs +++ b/src/NeoSharp.Core/Models/IssueTransaction.cs @@ -1,5 +1,4 @@ -using System; -using NeoSharp.BinarySerialization; +using NeoSharp.BinarySerialization; using NeoSharp.Core.Converters; namespace NeoSharp.Core.Models @@ -9,12 +8,5 @@ public class IssueTransaction : Transaction { /// public IssueTransaction() : base(TransactionType.IssueTransaction) { } - - //public override bool Verify() - //{ - // if (Version > 1) throw new FormatException(nameof(Version)); - - // return base.Verify(); - //} } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/MinerTransaction.cs b/src/NeoSharp.Core/Models/MinerTransaction.cs index f0ba595f..e9ec55c8 100644 --- a/src/NeoSharp.Core/Models/MinerTransaction.cs +++ b/src/NeoSharp.Core/Models/MinerTransaction.cs @@ -1,9 +1,6 @@ -using System; -using System.IO; -using System.Linq; +using System.IO; using NeoSharp.BinarySerialization; using NeoSharp.Core.Converters; -using NeoSharp.Core.Types; namespace NeoSharp.Core.Models { @@ -30,18 +27,5 @@ protected override int SerializeExclusiveData(IBinarySerializer serializer, Bina return 4; } #endregion - - //public override bool Verify() - //{ - // if (Version != 0) throw new FormatException(nameof(Version)); - - // if (Inputs.Length != 0) - // throw new FormatException(nameof(Inputs)); - - // if (Outputs.Any(p => p.AssetId != TransactionContext.UtilityTokenHash)) - // throw new FormatException(nameof(Outputs)); - - // return base.Verify(); - //} } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/OperationManger/BlockOperationsManager.cs b/src/NeoSharp.Core/Models/OperationManger/BlockOperationsManager.cs index 52ea7234..f8c746e6 100644 --- a/src/NeoSharp.Core/Models/OperationManger/BlockOperationsManager.cs +++ b/src/NeoSharp.Core/Models/OperationManger/BlockOperationsManager.cs @@ -11,7 +11,7 @@ public class BlockOperationsManager : IBlockOperationsManager #region Private Fields private readonly Crypto _crypto; private readonly IBinarySerializer _binarySerializer; - private readonly ITransactionOperationsManager _transactionOperationsManager; + private readonly ITransactionSigner _transactionSigner; private readonly IWitnessOperationsManager _witnessOperationsManager; #endregion @@ -19,12 +19,12 @@ public class BlockOperationsManager : IBlockOperationsManager public BlockOperationsManager( Crypto crypto, IBinarySerializer binarySerializer, - ITransactionOperationsManager transactionOperationsManager, + ITransactionSigner transactionSigner, IWitnessOperationsManager witnessOperationsManager) { this._crypto = crypto; this._binarySerializer = binarySerializer; - this._transactionOperationsManager = transactionOperationsManager; + this._transactionSigner = transactionSigner; this._witnessOperationsManager = witnessOperationsManager; } #endregion @@ -38,7 +38,7 @@ public void Sign(Block block) for (var x = 0; x < txSize; x++) { - this._transactionOperationsManager.Sign(block.Transactions?[x]); + this._transactionSigner.Sign(block.Transactions?[x]); block.TransactionHashes[x] = block.Transactions?[x].Hash; } diff --git a/src/NeoSharp.Core/Models/OperationManger/ITransactionOperationsManager.cs b/src/NeoSharp.Core/Models/OperationManger/ITransactionSigner.cs similarity index 52% rename from src/NeoSharp.Core/Models/OperationManger/ITransactionOperationsManager.cs rename to src/NeoSharp.Core/Models/OperationManger/ITransactionSigner.cs index f91c6ea3..3b45f04b 100644 --- a/src/NeoSharp.Core/Models/OperationManger/ITransactionOperationsManager.cs +++ b/src/NeoSharp.Core/Models/OperationManger/ITransactionSigner.cs @@ -1,9 +1,7 @@ namespace NeoSharp.Core.Models.OperationManger { - public interface ITransactionOperationsManager + public interface ITransactionSigner { void Sign(Transaction transaction); - - bool Verify(Transaction transaction); } } diff --git a/src/NeoSharp.Core/Models/OperationManger/TransactionOperationsManager.cs b/src/NeoSharp.Core/Models/OperationManger/TransactionOperationsManager.cs deleted file mode 100644 index d418c60d..00000000 --- a/src/NeoSharp.Core/Models/OperationManger/TransactionOperationsManager.cs +++ /dev/null @@ -1,43 +0,0 @@ -using NeoSharp.BinarySerialization; -using NeoSharp.Core.Cryptography; -using NeoSharp.Core.Types; - -namespace NeoSharp.Core.Models.OperationManger -{ - public class TransactionOperationsManager : ITransactionOperationsManager - { - #region Private Fields - private readonly Crypto _crypto; - private readonly IWitnessOperationsManager _witnessOperationsManager; - #endregion - - #region Constructor - public TransactionOperationsManager(Crypto crypto, IWitnessOperationsManager witnessOperationsManager) - { - this._crypto = crypto; - this._witnessOperationsManager = witnessOperationsManager; - } - #endregion - - #region ITransactionOperationsManager implementation - public void Sign(Transaction transaction) - { - transaction.Hash = new UInt256(this._crypto.Hash256(BinarySerializer.Default.Serialize(transaction, new BinarySerializerSettings - { - Filter = a => a != nameof(transaction.Witness) - }))); - - if (transaction.Witness == null) return; - foreach (var witness in transaction.Witness) - { - this._witnessOperationsManager.Sign(witness); - } - } - - public bool Verify(Transaction transaction) - { - throw new System.NotImplementedException(); - } - #endregion - } -} \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/OperationManger/TransactionSigner.cs b/src/NeoSharp.Core/Models/OperationManger/TransactionSigner.cs new file mode 100644 index 00000000..258faae2 --- /dev/null +++ b/src/NeoSharp.Core/Models/OperationManger/TransactionSigner.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NeoSharp.BinarySerialization; +using NeoSharp.Core.Blockchain; +using NeoSharp.Core.Cryptography; +using NeoSharp.Core.Extensions; +using NeoSharp.Core.Types; + +namespace NeoSharp.Core.Models.OperationManger +{ + public class TransactionSigner : ITransactionSigner + { + #region Private Fields + private readonly Crypto _crypto; + private readonly IWitnessOperationsManager _witnessOperationsManager; + #endregion + + #region Constructor + public TransactionSigner(Crypto crypto, IWitnessOperationsManager witnessOperationsManager) + { + _crypto = crypto; + _witnessOperationsManager = witnessOperationsManager; + } + #endregion + + + public void Sign(Transaction transaction) + { + transaction.Hash = new UInt256(_crypto.Hash256(BinarySerializer.Default.Serialize(transaction, new BinarySerializerSettings + { + Filter = a => a != nameof(transaction.Witness) + }))); + + if (transaction.Witness == null) return; + foreach (var witness in transaction.Witness) + { + _witnessOperationsManager.Sign(witness); + } + } + + } +} \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/OperationManger/TransactionVerifier.cs b/src/NeoSharp.Core/Models/OperationManger/TransactionVerifier.cs new file mode 100644 index 00000000..7e372c43 --- /dev/null +++ b/src/NeoSharp.Core/Models/OperationManger/TransactionVerifier.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NeoSharp.Core.Blockchain; +using NeoSharp.Core.Blockchain.Processing; +using NeoSharp.Core.Extensions; +using NeoSharp.Core.Types; + +namespace NeoSharp.Core.Models.OperationManger +{ + public class TransactionVerifier : ITransactionVerifier + { + + private readonly IWitnessOperationsManager _witnessOperationsManager; + private readonly IBlockchain _blockchain; + private readonly ITransactionContext _transactionContext; + + public TransactionVerifier(IWitnessOperationsManager witnessOperationsManager, + IBlockchain blockchain, ITransactionContext transactionContext) + { + _witnessOperationsManager = witnessOperationsManager; + _blockchain = blockchain; + _transactionContext = transactionContext; + } + + public bool Verify(Transaction transaction) + { + if (transaction.Attributes.Any(p => + p.Usage == TransactionAttributeUsage.ECDH02 || p.Usage == TransactionAttributeUsage.ECDH03)) + { + return false; + } + + for (var i = 1; i < transaction.Inputs.Length; i++) + { + for (var j = 0; j < i; j++) + { + if (transaction.Inputs[i].PrevHash == transaction.Inputs[j].PrevHash + && transaction.Inputs[i].PrevIndex == transaction.Inputs[j].PrevIndex) + { + return false; + } + } + } + + if (_blockchain.IsDoubleSpend(transaction)) + { + return false; + } + + foreach (var group in transaction.Outputs.GroupBy(p => p.AssetId)) + { + var asset = _blockchain.GetAsset(group.Key).Result; + + if (asset == null) + { + return false; + } + + // TODO: Should we check for `asset.Expiration <= _blockchain.Height + 1` ?? + if (asset.AssetType != AssetType.GoverningToken + && asset.AssetType != AssetType.UtilityToken) + { + return false; + } + + var tenPoweredToEightMinusAssetPrecision = (long) Math.Pow(10, 8 - asset.Precision); + + if (group.Any(output => output.Value.Value % tenPoweredToEightMinusAssetPrecision != 0)) + { + return false; + } + } + + var results = GetTransactionResults(transaction)?.ToArray(); + + if (results == null) + { + return false; + } + + var resultsDestroy = results.Where(p => p.Amount > Fixed8.Zero).ToArray(); + + if (resultsDestroy.Length > 1) + { + return false; + } + + if (resultsDestroy.Length == 1 + && resultsDestroy[0].AssetId != _transactionContext.UtilityTokenHash) + { + return false; + } + + if (_transactionContext.GetSystemFee(transaction) > Fixed8.Zero + && (resultsDestroy.Length == 0 + || resultsDestroy[0].Amount < _transactionContext.GetSystemFee(transaction))) + { + return false; + } + + var resultsIssue = results.Where(p => p.Amount < Fixed8.Zero).ToArray(); + + if (resultsIssue.Any(p => p.AssetId != _transactionContext.UtilityTokenHash) + && (transaction.Type == TransactionType.ClaimTransaction + || transaction.Type == TransactionType.IssueTransaction)) + { + return false; + } + + if (transaction.Type != TransactionType.MinerTransaction + && resultsIssue.Length > 0) + { + return false; + } + + // TODO: Verify Receiving Scripts? + + if (transaction.Witness.Any(witness => !_witnessOperationsManager.Verify(witness))) + { + return false; + } + + return true; + } + + private IEnumerable GetTransactionResults(Transaction transaction) + { + return GetReferences(transaction)?.Values.Select(p => new + { + p.AssetId, + p.Value + }).Concat(transaction.Outputs.Select(p => new + { + p.AssetId, + Value = -p.Value + })).GroupBy(p => p.AssetId, (k, g) => new TransactionResult + { + AssetId = k, + Amount = g.Sum(p => p.Value) + }).Where(p => p.Amount != Fixed8.Zero); + } + + private class TransactionResult + { + public UInt256 AssetId; + public Fixed8 Amount; + } + + private Dictionary GetReferences(Transaction transaction) + { + var references = new Dictionary(); + + foreach (var group in transaction.Inputs.GroupBy(p => p.PrevHash)) + { + var tx = _blockchain.GetTransaction(group.Key).Result; + + if (tx == null) + { + references = null; + break; + } + + foreach (var p in group) + { + if (tx.Outputs.Length > p.PrevIndex) + { + references.Add(p, tx.Outputs[p.PrevIndex]); + } + } + } + + return references; + } + } +} \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/PublishTransaction.cs b/src/NeoSharp.Core/Models/PublishTransaction.cs index 5bbefcb3..63739bab 100644 --- a/src/NeoSharp.Core/Models/PublishTransaction.cs +++ b/src/NeoSharp.Core/Models/PublishTransaction.cs @@ -82,12 +82,5 @@ protected override int SerializeExclusiveData(IBinarySerializer serializer, Bina } #endregion - - //public override bool Verify() - //{ - // if (Version > 1) throw new FormatException(nameof(Version)); - - // return base.Verify(); - //} } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/RegisterTransaction.cs b/src/NeoSharp.Core/Models/RegisterTransaction.cs index 607ade6d..51847c2f 100644 --- a/src/NeoSharp.Core/Models/RegisterTransaction.cs +++ b/src/NeoSharp.Core/Models/RegisterTransaction.cs @@ -66,21 +66,5 @@ protected override int SerializeExclusiveData(IBinarySerializer serializer, Bina return l; } - - //public override bool Verify() - //{ - // if (Version != 0) throw new FormatException(nameof(Version)); - - // if (Owner.IsInfinity && AssetType != AssetType.GoverningToken && AssetType != AssetType.UtilityToken) - // throw new FormatException(); - - // if (AssetType == AssetType.GoverningToken && !Hash.Equals(TransactionContext.GoverningTokenHash)) - // throw new FormatException(); - - // if (AssetType == AssetType.UtilityToken && !Hash.Equals(TransactionContext.UtilityTokenHash)) - // throw new FormatException(); - - // return base.Verify(); - //} } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/Transaction.cs b/src/NeoSharp.Core/Models/Transaction.cs index 3a19b4e9..10779d5f 100644 --- a/src/NeoSharp.Core/Models/Transaction.cs +++ b/src/NeoSharp.Core/Models/Transaction.cs @@ -176,10 +176,5 @@ protected virtual int SerializeExclusiveData(IBinarySerializer serializer, Binar } #endregion - - //public virtual bool Verify() - //{ - // return true; - //} } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/TransactionBase.cs b/src/NeoSharp.Core/Models/TransactionBase.cs deleted file mode 100644 index 122a7a0b..00000000 --- a/src/NeoSharp.Core/Models/TransactionBase.cs +++ /dev/null @@ -1,49 +0,0 @@ -using NeoSharp.BinarySerialization; -using NeoSharp.Core.Cryptography; -using NeoSharp.Core.Types; -using Newtonsoft.Json; - -namespace NeoSharp.Core.Models -{ - public abstract class TransactionBase - { - #region Public Properties - [BinaryProperty(0)] - [JsonProperty("hash")] - public UInt256 Hash { get; private set; } - - [BinaryProperty(1)] - [JsonProperty("type")] - public TransactionType Type { get; private set; } - - [BinaryProperty(2)] - [JsonProperty("version")] - public byte Version { get; private set; } - - [BinaryProperty(100)] - [JsonProperty("attributes")] - public TransactionAttribute[] Attributes = new TransactionAttribute[0]; - - [BinaryProperty(101)] - [JsonProperty("vin")] - public CoinReference[] Inputs = new CoinReference[0]; - - [BinaryProperty(102)] - [JsonProperty("vout")] - public TransactionOutput[] Outputs = new TransactionOutput[0]; - #endregion - - #region Protected Methods - public void Sign(TransactionBase transactionBase, byte[] signingSettings) - { - this.Type = transactionBase.Type; - this.Version = transactionBase.Version; - this.Attributes = transactionBase.Attributes; - this.Inputs = transactionBase.Inputs; - this.Outputs = transactionBase.Outputs; - - this.Hash = new UInt256(Crypto.Default.Hash256(signingSettings)); - } - #endregion - } -} diff --git a/src/NeoSharp.Core/Models/Witness.cs b/src/NeoSharp.Core/Models/Witness.cs index 801015f0..f72ecf32 100644 --- a/src/NeoSharp.Core/Models/Witness.cs +++ b/src/NeoSharp.Core/Models/Witness.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using NeoSharp.BinarySerialization; -using NeoSharp.Core.Cryptography; using NeoSharp.Core.Types; using Newtonsoft.Json; @@ -72,18 +71,5 @@ public override int GetHashCode() return l; } - - /// - /// Update Hash - /// - public void UpdateHash() - { - this.Hash = new UInt160(Crypto.Default.Hash160(GetHashData())); - } - - private byte[] GetHashData() - { - return VerificationScript; - } } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Models/WitnessBase.cs b/src/NeoSharp.Core/Models/WitnessBase.cs deleted file mode 100644 index 41d988a8..00000000 --- a/src/NeoSharp.Core/Models/WitnessBase.cs +++ /dev/null @@ -1,34 +0,0 @@ -using NeoSharp.BinarySerialization; -using NeoSharp.Core.Cryptography; -using NeoSharp.Core.Types; -using Newtonsoft.Json; - -namespace NeoSharp.Core.Models -{ - public abstract class WitnessBase - { - #region Public Properties - [JsonProperty("txid")] - public UInt160 Hash { get; private set; } - - [BinaryProperty(0, MaxLength = 65536)] - [JsonProperty("invocation")] - public byte[] InvocationScript { get; private set; } - - [BinaryProperty(1, MaxLength = 65536)] - [JsonProperty("verification")] - public byte[] VerificationScript { get; private set; } - #endregion - - #region Protected Methods - - protected void Sign(WitnessBase witnessBase) - { - this.InvocationScript = witnessBase.InvocationScript; - this.VerificationScript = witnessBase.VerificationScript; - - this.Hash = new UInt160(Crypto.Default.Hash160(this.VerificationScript)); - } - #endregion - } -} diff --git a/src/NeoSharp.Core/NeoSharp.Core.csproj b/src/NeoSharp.Core/NeoSharp.Core.csproj index 6a203be8..732375af 100644 --- a/src/NeoSharp.Core/NeoSharp.Core.csproj +++ b/src/NeoSharp.Core/NeoSharp.Core.csproj @@ -33,4 +33,9 @@ + + + ..\..\..\..\Users\esqueleto\.nuget\packages\simpleinjector\4.3.0\lib\netstandard1.3\SimpleInjector.dll + + \ No newline at end of file diff --git a/src/NeoSharp.Core/Network/BlockchainContext.cs b/src/NeoSharp.Core/Network/BlockchainContext.cs new file mode 100644 index 00000000..002c68c9 --- /dev/null +++ b/src/NeoSharp.Core/Network/BlockchainContext.cs @@ -0,0 +1,36 @@ +using NeoSharp.Core.Models; + +namespace NeoSharp.Core.Network +{ + public class BlockchainContext : IBlockchainContext + { + #region Private Fields + private uint _peerCurrentBlockIndex; + #endregion + + #region IBlockchainContext implementation + public Block CurrentBlock { get; set; } + + public BlockHeader LastBlockHeader { get; set; } + + public bool NeedPeerSync + { + get + { + if (this.LastBlockHeader == null) return true; + + return this.LastBlockHeader.Index < this._peerCurrentBlockIndex; + } + } + + public bool IsPeerConnected => this._peerCurrentBlockIndex != 0; + + public bool IsSyncing { get; set; } + + public void SetPeerCurrentBlockIndex(uint index) + { + this._peerCurrentBlockIndex = index; + } + #endregion + } +} \ No newline at end of file diff --git a/src/NeoSharp.Core/Network/IBlockchainContext.cs b/src/NeoSharp.Core/Network/IBlockchainContext.cs new file mode 100644 index 00000000..67e90131 --- /dev/null +++ b/src/NeoSharp.Core/Network/IBlockchainContext.cs @@ -0,0 +1,19 @@ +using NeoSharp.Core.Models; + +namespace NeoSharp.Core.Network +{ + public interface IBlockchainContext + { + Block CurrentBlock { get; set; } + + BlockHeader LastBlockHeader { get; set; } + + bool NeedPeerSync { get; } + + bool IsSyncing { get; set; } + + bool IsPeerConnected { get; } + + void SetPeerCurrentBlockIndex(uint index); + } +} diff --git a/src/NeoSharp.Core/Network/IPeer.cs b/src/NeoSharp.Core/Network/IPeer.cs index 5ddb299f..f288fb69 100644 --- a/src/NeoSharp.Core/Network/IPeer.cs +++ b/src/NeoSharp.Core/Network/IPeer.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using NeoSharp.Core.Cryptography; using NeoSharp.Core.Messaging; using NeoSharp.Core.Messaging.Messages; diff --git a/src/NeoSharp.Core/Network/PeerMessageListener.cs b/src/NeoSharp.Core/Network/PeerMessageListener.cs index 5fc4bdbd..f8d45db0 100644 --- a/src/NeoSharp.Core/Network/PeerMessageListener.cs +++ b/src/NeoSharp.Core/Network/PeerMessageListener.cs @@ -15,7 +15,7 @@ public class PeerMessageListener : IPeerMessageListener private static readonly TimeSpan DefaultMessagePollingInterval = TimeSpan.FromMilliseconds(100); private readonly IAsyncDelayer _asyncDelayer; - private readonly IMessageHandler _messageHandler; + private readonly IMessageHandlerProxy _messageHandlerProxy; private readonly IServerContext _serverContext; #endregion @@ -24,11 +24,11 @@ public class PeerMessageListener : IPeerMessageListener public PeerMessageListener( IAsyncDelayer asyncDelayer, - IMessageHandler messageHandler, + IMessageHandlerProxy messageHandlerProxy, IServerContext serverContext) { _asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); - _messageHandler = messageHandler ?? throw new ArgumentNullException(nameof(messageHandler)); + _messageHandlerProxy = messageHandlerProxy ?? throw new ArgumentNullException(nameof(messageHandlerProxy)); _serverContext = serverContext ?? throw new ArgumentNullException(nameof(serverContext)); } @@ -55,7 +55,7 @@ public void StartFor(IPeer peer, CancellationToken cancellationToken) // TODO #369: Peer that sending wrong messages has to be disconnected. if (peer.IsReady == message.IsHandshakeMessage()) continue; - await _messageHandler.Handle(message, peer); + await _messageHandlerProxy.Handle(message, peer); } }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); } diff --git a/src/NeoSharp.Core/Network/Server.cs b/src/NeoSharp.Core/Network/Server.cs index 3bac3a37..2260b15b 100644 --- a/src/NeoSharp.Core/Network/Server.cs +++ b/src/NeoSharp.Core/Network/Server.cs @@ -76,7 +76,7 @@ public class Server : IServer, IBroadcaster, IDisposable #region IServer implementation /// - public IReadOnlyCollection ConnectedPeers => _connectedPeers.ToArray(); + public IReadOnlyCollection ConnectedPeers => _connectedPeers.Where(x => x.IsConnected).ToArray(); /// public void Start() diff --git a/src/NeoSharp.Core/Network/ServerContext.cs b/src/NeoSharp.Core/Network/ServerContext.cs index 6e3eaea1..907e4775 100644 --- a/src/NeoSharp.Core/Network/ServerContext.cs +++ b/src/NeoSharp.Core/Network/ServerContext.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using NeoSharp.Core.Blockchain; using NeoSharp.Core.Extensions; using NeoSharp.Core.Messaging.Messages; @@ -8,63 +7,51 @@ namespace NeoSharp.Core.Network { public class ServerContext : IServerContext { - #region Consts + #region Private fields + private const uint ProtocolVersion = 0; + private const ulong NodeNetwork = 1; - const uint PROTOCOL_VERSION = 0; - const ulong NODE_NETWORK = 1; - - #endregion - - #region Variables - - /// - /// Blockchain - /// - private readonly IBlockchain _blockchain; - /// - /// Cached version - /// + private readonly IBlockchainContext _blockchainContext; private readonly VersionPayload _version; - #endregion - #region Properties - + #region Public properties /// public VersionPayload Version { get { - _version.Timestamp = DateTime.UtcNow.ToTimestamp(); - _version.CurrentBlockIndex = _blockchain.CurrentBlock?.Index ?? 0; + this._version.Timestamp = DateTime.UtcNow.ToTimestamp(); + this._version.CurrentBlockIndex = this._blockchainContext.CurrentBlock?.Index ?? 0; return _version; } } - #endregion + #region Constructor /// /// Server context /// /// Config - /// Blockchain - public ServerContext(NetworkConfig config, IBlockchain blockchain) + /// Context information updated by blockchain. + public ServerContext(NetworkConfig config, IBlockchainContext blockchainContext) { if (config == null) throw new ArgumentNullException(nameof(config)); - _blockchain = blockchain ?? throw new ArgumentNullException(nameof(blockchain)); + this._blockchainContext = blockchainContext ?? throw new ArgumentNullException(nameof(blockchainContext)); _version = new VersionPayload { - Version = PROTOCOL_VERSION, - Services = NODE_NETWORK, + Version = ProtocolVersion, + Services = NodeNetwork, Timestamp = DateTime.UtcNow.ToTimestamp(), Port = config.Port, Nonce = (uint)new Random(Environment.TickCount).Next(), UserAgent = $"/NEO-Sharp:{Assembly.GetExecutingAssembly().GetName().Version.ToString(3)}/", - CurrentBlockIndex = _blockchain.CurrentBlock?.Index ?? 0, + CurrentBlockIndex = this._blockchainContext.CurrentBlock?.Index ?? 0, Relay = true }; } + #endregion } } diff --git a/src/NeoSharp.Core/Network/Tcp/TcpPeer.cs b/src/NeoSharp.Core/Network/Tcp/TcpPeer.cs index 28df6d9b..14ef0b3d 100644 --- a/src/NeoSharp.Core/Network/Tcp/TcpPeer.cs +++ b/src/NeoSharp.Core/Network/Tcp/TcpPeer.cs @@ -125,7 +125,7 @@ public bool ChangeProtocol(VersionPayload version) public void Disconnect() { Dispose(); - _logger.LogInformation("The peer was disconnected"); + _logger.LogInformation($"The peer {this.EndPoint.Host}:{this.EndPoint.Port} was disconnected"); } /// @@ -172,7 +172,6 @@ private void SendMessages(CancellationToken cancellationToken) { await InternalSend(message); } - } }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); @@ -222,7 +221,9 @@ public async Task Receive() try { - return await _protocol.ReceiveMessageAsync(_stream, tokenSource.Token); + var msg = await _protocol.ReceiveMessageAsync(_stream, tokenSource.Token); + this._logger.LogDebug($"Message Received: {msg.Command}"); + return msg; } catch (Exception err) { @@ -243,8 +244,10 @@ public async Task Receive() public async Task Receive() where TMessage : Message, new() { if (!IsConnected) return null; + var message = await Receive() as TMessage; + _logger.LogDebug($"Message Received: {message.Command}"); + return message; - return await Receive() as TMessage; } /// @@ -262,12 +265,12 @@ private async Task InternalSend(Message message) try { + _logger.LogDebug($"Message sent: {message.Command} to {this.EndPoint.Host}."); await _protocol.SendMessageAsync(_stream, message, tokenSource.Token); } catch (Exception err) { - _logger.LogError(err, "Error while send"); - + _logger.LogError(err, $"Error while send message {message.Command} to {this.EndPoint.Host}."); Disconnect(); } } diff --git a/src/NeoSharp.Core/Network/Tcp/TcpPeerFactory.cs b/src/NeoSharp.Core/Network/Tcp/TcpPeerFactory.cs index f6464334..ef763e49 100644 --- a/src/NeoSharp.Core/Network/Tcp/TcpPeerFactory.cs +++ b/src/NeoSharp.Core/Network/Tcp/TcpPeerFactory.cs @@ -67,6 +67,7 @@ public async Task ConnectTo(EndPoint endPoint) _logger.LogInformation($"Connecting to {ipEp}..."); var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + //socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); await socket.ConnectAsync(ipEp.Address, ipEp.Port); _logger.LogInformation($"Connected to {ipEp}"); diff --git a/src/NeoSharp.Core/Types/ITransactionContext.cs b/src/NeoSharp.Core/Types/ITransactionContext.cs new file mode 100644 index 00000000..c7423d0d --- /dev/null +++ b/src/NeoSharp.Core/Types/ITransactionContext.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Linq; +using NeoSharp.Core.Blockchain; +using NeoSharp.Core.Models; + +namespace NeoSharp.Core.Types +{ + public interface ITransactionContext + { + Fixed8 DefaultSystemFee { get; } + UInt256 UtilityTokenHash { get; } + UInt256 GoverningTokenHash { get; } + Fixed8 GetSystemFee(Transaction tx); + } +} \ No newline at end of file diff --git a/src/NeoSharp.Core/Types/TransactionContext.cs b/src/NeoSharp.Core/Types/TransactionContext.cs index 96241a62..7f240249 100644 --- a/src/NeoSharp.Core/Types/TransactionContext.cs +++ b/src/NeoSharp.Core/Types/TransactionContext.cs @@ -5,74 +5,68 @@ namespace NeoSharp.Core.Types { - public class TransactionContext + public class TransactionContext : ITransactionContext { - // TODO #362: How to inject this - - public static readonly Fixed8 DefaultSystemFee = Fixed8.Zero;// Settings.Default.SystemFee.TryGetValue(Type, out Fixed8 fee) ? fee : Fixed8.Zero; - public static readonly UInt256 UtilityTokenHash = UInt256.Zero, GoverningTokenHash = UInt256.Zero; + public Fixed8 DefaultSystemFee => Fixed8.Zero; // Settings.Default.SystemFee.TryGetValue(Type, out Fixed8 fee) ? fee : Fixed8.Zero; + public UInt256 UtilityTokenHash => UInt256.Zero; + public UInt256 GoverningTokenHash => UInt256.Zero; // --------------------------- private IReadOnlyDictionary _references; - public readonly IBlockchain Blockchain = null; - private readonly Transaction _tx; private Fixed8 _systemFee = -Fixed8.Satoshi, _network_fee = -Fixed8.Satoshi; /// /// System Fee /// - public Fixed8 SystemFee + public Fixed8 GetSystemFee(Transaction tx) { - get + if (_systemFee == -Fixed8.Satoshi) { - if (_systemFee == -Fixed8.Satoshi) - { - _systemFee = DefaultSystemFee; + _systemFee = DefaultSystemFee; - switch (_tx.Type) - { - case TransactionType.InvocationTransaction: + switch (tx.Type) + { + case TransactionType.InvocationTransaction: + { + InvocationTransaction itx = (InvocationTransaction)tx; + _systemFee = itx.Gas; + + break; + } + case TransactionType.IssueTransaction: + { + if (tx.Version >= 1) { - InvocationTransaction itx = (InvocationTransaction)_tx; - _systemFee = itx.Gas; - - break; + _systemFee = Fixed8.Zero; + return _systemFee; } - case TransactionType.IssueTransaction: - { - if (_tx.Version >= 1) - { - _systemFee = Fixed8.Zero; - return _systemFee; - } - if (_tx.Outputs.All(p => p.AssetId == GoverningTokenHash || p.AssetId == UtilityTokenHash)) - _systemFee = Fixed8.Zero; + if (tx.Outputs.All(p => p.AssetId == GoverningTokenHash || p.AssetId == UtilityTokenHash)) + _systemFee = Fixed8.Zero; - break; - } - case TransactionType.RegisterTransaction: - { - var rtx = (RegisterTransaction) _tx; + break; + } + case TransactionType.RegisterTransaction: + { + var rtx = (RegisterTransaction) tx; - if (rtx.AssetType == AssetType.GoverningToken || rtx.AssetType == AssetType.UtilityToken) - _systemFee = Fixed8.Zero; + if (rtx.AssetType == AssetType.GoverningToken || rtx.AssetType == AssetType.UtilityToken) + _systemFee = Fixed8.Zero; - break; - } - case TransactionType.StateTransaction: - { - StateTransaction stx = (StateTransaction)_tx; - _systemFee = new Fixed8(stx.Descriptors.Sum(p => p.SystemFee.Value)); + break; + } + case TransactionType.StateTransaction: + { + StateTransaction stx = (StateTransaction)tx; + _systemFee = new Fixed8(stx.Descriptors.Sum(p => p.SystemFee.Value)); - break; - } - } + break; + } } - return _systemFee; } + return _systemFee; } // TODO #361 [AboimPinto]: This logic need to be done in different way because we cannot await a method in the 'get' body. @@ -138,16 +132,5 @@ public Fixed8 SystemFee // return _references; // } //} - - /// - /// Constructor - /// - /// Transaction - /// Blockchain - public TransactionContext(Transaction tx, IBlockchain blockchain) - { - _tx = tx; - Blockchain = blockchain; - } } } \ No newline at end of file diff --git a/src/NeoSharp.Core/Wallet/Helpers/WalletHelper.cs b/src/NeoSharp.Core/Wallet/Helpers/WalletHelper.cs index d0a73f6d..4fe2e422 100644 --- a/src/NeoSharp.Core/Wallet/Helpers/WalletHelper.cs +++ b/src/NeoSharp.Core/Wallet/Helpers/WalletHelper.cs @@ -31,7 +31,7 @@ public byte[] DecryptWif(string encryptedPrivateKey, SecureString passphrase) throw new ArgumentNullException(nameof(encryptedPrivateKey)); } - if (passphrase == null || String.IsNullOrWhiteSpace(passphrase.ToString())) + if (passphrase == null || String.IsNullOrWhiteSpace(passphrase.ToString())) { throw new ArgumentNullException(nameof(passphrase)); } @@ -162,6 +162,46 @@ public UInt160 ScriptHashFromPublicKey(ECPoint publicKey) return ContractFactory.CreateSinglePublicKeyRedeemContract(publicKey).ScriptHash; } + /// + /// Converts a byte array into wif string + /// + /// Wif. + /// Private Key + public string PrivateKeyToWif(byte[] privateKey) + { + byte[] data = new byte[34]; + data[0] = 0x80; + Buffer.BlockCopy(privateKey, 0, data, 1, 32); + data[33] = 0x01; + string wif = Crypto.Default.Base58CheckEncode(data); + Array.Clear(data, 0, data.Length); + return wif; + } + + /// + /// Gets the private key from wif. + /// + /// The private key from wif. + /// Wif. + public byte[] GetPrivateKeyFromWIF(string wif) + { + var internalWif = wif ?? throw new ArgumentNullException(nameof(wif)); + + var privateKeyByteArray = Crypto.Default.Base58CheckDecode(internalWif); + + if (privateKeyByteArray.IsValidPrivateKey()) + { + var privateKey = new byte[32]; + Buffer.BlockCopy(privateKeyByteArray, 1, privateKey, 0, privateKey.Length); + Array.Clear(privateKeyByteArray, 0, privateKeyByteArray.Length); + return privateKey; + } + else + { + throw new FormatException(); + } + } + #region Private Methods /// diff --git a/src/NeoSharp.Core/Wallet/IWalletManager.cs b/src/NeoSharp.Core/Wallet/IWalletManager.cs index 86822843..554f8044 100644 --- a/src/NeoSharp.Core/Wallet/IWalletManager.cs +++ b/src/NeoSharp.Core/Wallet/IWalletManager.cs @@ -48,7 +48,14 @@ public interface IWalletManager void DeleteAccount(UInt160 scriptHash); /// - /// Gets the account. + /// Gets the account using the account (label property). + /// + /// The account. + /// Scripthash's account. + IWalletAccount GetAccount(string alias); + + /// + /// Gets the account using the account scripthash. /// /// The account. /// Scripthash's account. @@ -106,25 +113,42 @@ public interface IWalletManager IWalletAccount ImportEncryptedWif(string nep2, SecureString password); /// - /// Verifies the password. + /// Saves the current wallet into the HD /// - /// true, if password was verifyed, false - /// otherwise. - /// Wallet accout. - /// Password. - bool VerifyPassword(IWalletAccount walletAccout, SecureString password); + void SaveWallet(); /// /// Checks the wallet is open. /// void CheckWalletIsOpen(); + /// + /// Check if the password provided is the same used in the first wallet account. + /// + void CheckIfPasswordMatchesOpenWallet(SecureString password); + /// /// save the open wallet into a specific filename /// /// the filename void ExportWallet(string filename); + /// + /// Returns the private key from a NEP2 key and password + /// + /// The nep2 key. + /// Nep2key. + /// Key password. + byte[] DecryptNep2(string nep2key, SecureString keyPassword); + + /// + /// Returns the encrypted private key (nep-2) + /// + /// The nep2. + /// Private key. + /// Key password. + string EncryptNep2(byte[] privateKey, SecureString keyPassword); + /// /// Load a wallet at specified fileName. /// @@ -135,5 +159,26 @@ public interface IWalletManager /// Close wallet. /// void Close(); + + /// + /// Converts a byte array into a wif string + /// + /// Private key in wif format. + /// Private key. + string PrivateKeyToWif(byte[] privateKey); + + /// + /// Gets the private key from wif. + /// + /// The private key from wif. + /// Wif. + byte[] GetPrivateKeyFromWIF(string wif); + + /// + /// Adds/replaces an account alias (label) + /// + /// Account scripthash. + /// Account label + void UpdateAccountAlias(UInt160 scripthash, string alias); } } diff --git a/src/NeoSharp.Core/Wallet/NEP6/NEP6WalletManager.cs b/src/NeoSharp.Core/Wallet/NEP6/NEP6WalletManager.cs index e7efb520..7268129d 100644 --- a/src/NeoSharp.Core/Wallet/NEP6/NEP6WalletManager.cs +++ b/src/NeoSharp.Core/Wallet/NEP6/NEP6WalletManager.cs @@ -35,6 +35,8 @@ public Nep6WalletManager(IFileWrapper fileWrapper, IJsonConverter jsonConverter) _jsonConverter = jsonConverter; } + + /// public void CreateWallet(string filename) { @@ -83,13 +85,12 @@ public IWalletAccount CreateAndAddAccount(SecureString password) public IWalletAccount CreateAccount(SecureString password) { CheckWalletIsOpen(); - byte[] passwordHash; - ValidateAccountsPasswordMismatch(password, out passwordHash); + CheckIfPasswordMatchesOpenWallet(password); var privateKey = Crypto.Default.GenerateRandomBytes(32); var account = ImportPrivateKey(privateKey, password); Array.Clear(privateKey, 0, privateKey.Length); - _accountPasswordHashCache = passwordHash; + _accountPasswordHashCache = GetPasswordHash(password); return account; } @@ -106,6 +107,19 @@ public void DeleteAccount(UInt160 scriptHash) SaveWallet(); } + public IWalletAccount GetAccount(string alias) + { + if (alias == null) + { + throw new ArgumentNullException(); + } + CheckWalletIsOpen(); + + return Wallet.Accounts + .Where(x => x.Label.Equals(alias)) + .FirstOrDefault(); + } + /// public IWalletAccount GetAccount(UInt160 scriptHash) { @@ -133,6 +147,14 @@ public IWalletAccount GetAccount(ECPoint pubkey) return GetAccount(scriptHash); } + /// + public void UpdateAccountAlias(UInt160 scripthash, string alias) + { + var account = GetAccount(scripthash); + account.Label = alias; + SaveWallet(); + } + /// public IWalletAccount ImportScriptHash(UInt160 scriptHash) { @@ -182,6 +204,18 @@ public IWalletAccount ImportPrivateKey(byte[] privateKey, SecureString passphras return account; } + /// + public byte[] GetPrivateKeyFromWIF(string wif) + { + return _walletHelper.GetPrivateKeyFromWIF(wif); + } + + /// + public string PrivateKeyToWif(byte[] privateKey) + { + return _walletHelper.PrivateKeyToWif(privateKey); + } + /// public IWalletAccount ImportWif(string wif, SecureString password) { @@ -207,26 +241,6 @@ public IWalletAccount ImportEncryptedWif(string nep2, SecureString passphrase) return account; } - /// - public bool VerifyPassword(IWalletAccount walletAccout, SecureString password) - { - if (walletAccout == null) - { - throw new ArgumentException(); - } - - try - { - _walletHelper.DecryptWif(walletAccout.Key, password); - } - - catch (FormatException) - { - return false; - } - - return true; - } /// public void ExportWallet(String filename) @@ -240,6 +254,7 @@ public void ExportWallet(String filename) _fileWrapper.WriteToFile(json, filename); } + /// public void Load(string fileName) { @@ -275,6 +290,18 @@ public ECPoint GetPublicKeyFromNep2(string nep2Key, SecureString password) return new ECPoint(publicKeyInBytes); } + /// + public byte[] DecryptNep2(string nep2key, SecureString keyPassword) + { + return _walletHelper.DecryptWif(nep2key, keyPassword); + } + + /// + public string EncryptNep2(byte[] privateKey, SecureString keyPassword) + { + return _walletHelper.EncryptWif(privateKey, keyPassword); + } + /// public void CheckWalletIsOpen() { @@ -284,6 +311,42 @@ public void CheckWalletIsOpen() } } + /// + public void CheckIfPasswordMatchesOpenWallet(SecureString password) + { + CheckWalletIsOpen(); + byte[] passwordHash = GetPasswordHash(password); + + if (_accountPasswordHashCache != null) + { + if (!passwordHash.SequenceEqual(_accountPasswordHashCache)) + { + throw new AccountsPasswordMismatchException(); + } + } + + if (Wallet.Accounts != null && Wallet.Accounts.Length > 0) + { + try + { + _walletHelper.DecryptWif(Wallet.Accounts.First().Key, password); + } + catch (FormatException) + { + throw new AccountsPasswordMismatchException(); + } + } + } + + /// + /// save the open wallet into the same file + /// + public void SaveWallet() + { + CheckWalletIsOpen(); + ExportWallet(_openWalletFilename); + } + /// /// Adds the or replace an account in the system. /// If the account with that scriptHash already exists, @@ -320,8 +383,6 @@ private void AddOrReplaceAccount(IWalletAccount account) SaveWallet(); } - - /// /// Retrieves the account from the Account list using the script hash/ /// Replaces the account information with those provided in the newAccountInformation parameter @@ -351,13 +412,7 @@ private IWalletAccount CloneAndUpdate(IWalletAccount newAccountInformation) return clonedAccount; } - /// - /// save the open wallet into the same file - /// - private void SaveWallet() - { - ExportWallet(_openWalletFilename); - } + /// /// Adds the account to the Account list. @@ -379,30 +434,6 @@ private void AddAccount(IWalletAccount account) } } - /// - /// Gets the private key from wif. - /// - /// The private key from wif. - /// Wif. - private byte[] GetPrivateKeyFromWIF(string wif) - { - var internalWif = wif ?? throw new ArgumentNullException(nameof(wif)); - - var privateKeyByteArray = Crypto.Default.Base58CheckDecode(internalWif); - - if (privateKeyByteArray.IsValidPrivateKey()) - { - var privateKey = new byte[32]; - Buffer.BlockCopy(privateKeyByteArray, 1, privateKey, 0, privateKey.Length); - Array.Clear(privateKeyByteArray, 0, privateKeyByteArray.Length); - return privateKey; - } - else - { - throw new FormatException(); - } - } - /// /// Creates the NEP6Account with private key. /// @@ -467,31 +498,5 @@ private void UnlockAccount(string nep2Key, ECPoint publicKey, byte[] privateKey) _unlockedAccounts.Add(nep2Key, entry); } } - - private void ValidateAccountsPasswordMismatch(SecureString password, out byte[] passwordHash) - { - CheckWalletIsOpen(); - - passwordHash = GetPasswordHash(password); - - if (_accountPasswordHashCache != null) { - if (!passwordHash.SequenceEqual(_accountPasswordHashCache)) - { - throw new AccountsPasswordMismatchException(); - } - } - else if (Wallet.Accounts != null && Wallet.Accounts.Length > 0) - { - try - { - _walletHelper.DecryptWif(Wallet.Accounts.First().Key, password); - } - catch (FormatException) - { - throw new AccountsPasswordMismatchException(); - } - } - } - } } \ No newline at end of file diff --git a/src/NeoSharp.DI.SimpleInjector/SimpleInjectorContainerBuilder.cs b/src/NeoSharp.DI.SimpleInjector/SimpleInjectorContainerBuilder.cs index 67ee4901..797a8ace 100644 --- a/src/NeoSharp.DI.SimpleInjector/SimpleInjectorContainerBuilder.cs +++ b/src/NeoSharp.DI.SimpleInjector/SimpleInjectorContainerBuilder.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; using NeoSharp.Core.DI; +using NeoSharp.Core.Extensions; +using NeoSharp.Core.Messaging; using SimpleInjector; namespace NeoSharp.DI.SimpleInjector @@ -94,6 +97,19 @@ public void Register(TService configuration) _container.RegisterSingleton(() => instanceCreator(_containerAdapter)); } + public void RegisterCollectionOf() + { + var messageHandlers = typeof(TService) + .Assembly + .GetExportedTypes() + .Where(x => x.IsClass && !x.IsAbstract && x.IsAssignableToGenericType(typeof(MessageHandler<>))); + var registrations = messageHandlers + .Select(x => Lifestyle.Singleton.CreateRegistration(x, _container)) + .ToArray(); + + _container.Collection.Register(typeof(TService), registrations); + } + public void RegisterModule() where TModule : class, IModule, new() { var module = new TModule(); diff --git a/test/NeoSharp.Application.Test/UtBlockchainModule.cs b/test/NeoSharp.Application.Test/UtBlockchainModule.cs index 728695ce..8c1c64a3 100644 --- a/test/NeoSharp.Application.Test/UtBlockchainModule.cs +++ b/test/NeoSharp.Application.Test/UtBlockchainModule.cs @@ -31,7 +31,8 @@ public void Register_AllObjectsAreCorrectlyRegister() containerBuilderMock.Verify(x => x.RegisterSingleton, InvocationTransactionPersister>(), Times.Once); containerBuilderMock.Verify(x => x.RegisterSingleton(), Times.Once); - containerBuilderMock.Verify(x => x.RegisterSingleton(), Times.Once); + containerBuilderMock.Verify(x => x.RegisterSingleton(), Times.Once); + containerBuilderMock.Verify(x => x.RegisterSingleton(), Times.Once); containerBuilderMock.Verify(x => x.RegisterSingleton(), Times.Once); containerBuilderMock.Verify(x => x.RegisterSingleton(), Times.Once); } diff --git a/test/NeoSharp.Core.Test/Messaging/Handlers/UtVerackMessageHandler.cs b/test/NeoSharp.Core.Test/Messaging/Handlers/UtVerackMessageHandler.cs index 7978ce8e..36575454 100644 --- a/test/NeoSharp.Core.Test/Messaging/Handlers/UtVerackMessageHandler.cs +++ b/test/NeoSharp.Core.Test/Messaging/Handlers/UtVerackMessageHandler.cs @@ -1,9 +1,7 @@ -using System.Linq; -using System.Threading.Tasks; +using System.Threading.Tasks; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using NeoSharp.Core.Blockchain; using NeoSharp.Core.Messaging.Handlers; using NeoSharp.Core.Messaging.Messages; using NeoSharp.Core.Models; @@ -17,22 +15,28 @@ namespace NeoSharp.Core.Test.Messaging.Handlers public class UtVerAckMessageHandler : TestBase { [TestMethod] - public async Task Can_activate_peer_on_verack_receiving() + public async Task Handle_VerAckMessageReceived_PeerIsReady() { // Arrange - var blockchain = new NullBlockchain(); - - AutoMockContainer.Register(blockchain); - var verAckMessage = new VerAckMessage(); - var version = new VersionPayload(); + var version = new VersionPayload + { + CurrentBlockIndex = 1 + }; var peerMock = AutoMockContainer.GetMock(); peerMock.SetupProperty(x => x.IsReady, false); peerMock.SetupProperty(x => x.Version, version); - blockchain.LastBlockHeader.Index = 1; - version.CurrentBlockIndex = 1; + var expectedLastBlockHeader = new BlockHeader(HeaderType.Header) + { + Index = 1 + }; + + this.AutoMockContainer + .GetMock() + .SetupGet(x => x.LastBlockHeader) + .Returns(expectedLastBlockHeader); var messageHandler = AutoMockContainer.Get(); @@ -40,30 +44,37 @@ public async Task Can_activate_peer_on_verack_receiving() await messageHandler.Handle(verAckMessage, peerMock.Object); // Assert - peerMock.Object.IsReady.Should().BeTrue(); + peerMock.Object.IsReady + .Should() + .BeTrue(); } [TestMethod] - public async Task Can_send_get_block_headers_message_if_peer_block_header_height_is_different() + public async Task Handle_LastLocalBlockIndex1LastPeerBlockIndex2_GetBlockMessageSend() { // Arrange - var blockHeader = new BlockHeader() + const uint currentBlockIndex = 2; + + var blockHeader = new BlockHeader { Index = 1, Hash = UInt256.Zero }; - var blockchainMock = this.AutoMockContainer.GetMock(); - blockchainMock + var blockchainContextMock = this.AutoMockContainer.GetMock(); + blockchainContextMock .SetupGet(x => x.LastBlockHeader) .Returns(blockHeader); + blockchainContextMock + .SetupGet(x => x.NeedPeerSync) + .Returns(true); var verAckMessage = new VerAckMessage(); var version = new VersionPayload(); var peerMock = AutoMockContainer.GetMock(); peerMock.SetupProperty(x => x.Version, version); - version.CurrentBlockIndex = 2; + version.CurrentBlockIndex = currentBlockIndex; var messageHandler = AutoMockContainer.Get(); @@ -71,8 +82,11 @@ public async Task Can_send_get_block_headers_message_if_peer_block_header_height await messageHandler.Handle(verAckMessage, peerMock.Object); // Assert + blockchainContextMock.Verify(x => x.SetPeerCurrentBlockIndex(currentBlockIndex)); // TODO #410: This need to evaluate correctly that the right GetBlockHeadersMessage is been generated. peerMock.Verify(x => x.Send(It.IsAny()), Times.Once); } + + // TODO #435: There aren't tests for the case of the node has more blocks then the peer node. } } \ No newline at end of file diff --git a/test/NeoSharp.Core.Test/Messaging/UtMessageHandlerProxy.cs b/test/NeoSharp.Core.Test/Messaging/UtMessageHandlerProxy.cs index 9268e987..ba28ba16 100644 --- a/test/NeoSharp.Core.Test/Messaging/UtMessageHandlerProxy.cs +++ b/test/NeoSharp.Core.Test/Messaging/UtMessageHandlerProxy.cs @@ -16,57 +16,57 @@ namespace NeoSharp.Core.Test.Messaging [TestClass] public class UtMessageHandlerProxy : TestBase { - private class NullVersionMessageHandler : IMessageHandler - { - public Task Handle(VersionMessage message, IPeer sender) - { - return Task.CompletedTask; - } - } + //private class NullVersionMessageHandler : IMessageHandler + //{ + // public Task Handle(VersionMessage message, IPeer sender) + // { + // return Task.CompletedTask; + // } + //} - [TestMethod] - public void Can_delegate_message_handling() - { - // Arrange - var serverContextMock = AutoMockContainer - .GetMock() - .SetupDefaultServerContext(); + //[TestMethod] + //public void Can_delegate_message_handling() + //{ + // // Arrange + // var serverContextMock = AutoMockContainer + // .GetMock() + // .SetupDefaultServerContext(); - var containerMock = AutoMockContainer.GetMock(); + // var containerMock = AutoMockContainer.GetMock(); - containerMock - .Setup(c => c.Resolve(It.IsAny())) - .Returns(() => new NullVersionMessageHandler()); + // containerMock + // .Setup(c => c.Resolve(It.IsAny())) + // .Returns(() => new NullVersionMessageHandler()); - var loggerMock = AutoMockContainer.GetMock>(); + // var loggerMock = AutoMockContainer.GetMock>(); - var messageHandlerProxy = new MessageHandlerProxy(containerMock.Object, new[] { typeof(NullVersionMessageHandler) }, loggerMock.Object); + // var messageHandlerProxy = new MessageHandlerProxy(containerMock.Object, new[] { typeof(NullVersionMessageHandler) }, loggerMock.Object); - // Act - var task = messageHandlerProxy.Handle(new VersionMessage(serverContextMock.Object.Version), null); - task.Wait(); + // // Act + // var task = messageHandlerProxy.Handle(new VersionMessage(serverContextMock.Object.Version), null); + // task.Wait(); - // Assert - task.IsCompletedSuccessfully.Should().Be(true); - } + // // Assert + // task.IsCompletedSuccessfully.Should().Be(true); + //} - [TestMethod] - public void Throw_on_receiving_of_unknown_message() - { - // Arrange - var serverContextMock = AutoMockContainer - .GetMock() - .SetupDefaultServerContext(); + //[TestMethod] + //public void Throw_on_receiving_of_unknown_message() + //{ + // // Arrange + // var serverContextMock = AutoMockContainer + // .GetMock() + // .SetupDefaultServerContext(); - var containerMock = AutoMockContainer.GetMock(); - var loggerMock = AutoMockContainer.GetMock>(); - var messageHandlerProxy = new MessageHandlerProxy(containerMock.Object, new Type[0], loggerMock.Object); + // var containerMock = AutoMockContainer.GetMock(); + // var loggerMock = AutoMockContainer.GetMock>(); + // var messageHandlerProxy = new MessageHandlerProxy(containerMock.Object, new Type[0], loggerMock.Object); - // Act - Action a = () => messageHandlerProxy.Handle(new VersionMessage(serverContextMock.Object.Version), null); + // // Act + // Action a = () => messageHandlerProxy.Handle(new VersionMessage(serverContextMock.Object.Version), null); - // Assert - a.Should().Throw(); - } + // // Assert + // a.Should().Throw(); + //} } } \ No newline at end of file diff --git a/test/NeoSharp.Core.Test/Models/UtTransactionVerifier.cs b/test/NeoSharp.Core.Test/Models/UtTransactionVerifier.cs new file mode 100644 index 00000000..bbc77c08 --- /dev/null +++ b/test/NeoSharp.Core.Test/Models/UtTransactionVerifier.cs @@ -0,0 +1,925 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using NeoSharp.Core.Blockchain; +using NeoSharp.Core.Blockchain.Processing; +using NeoSharp.Core.Models; +using NeoSharp.Core.Models.OperationManger; +using NeoSharp.Core.Types; +using NeoSharp.TestHelpers; + +namespace NeoSharp.Core.Test.Network +{ + [TestClass] + public class UtTransactionVerifier : TestBase + { + + [TestMethod] + public void Verify_AttributeUsageECDH02() + { + var testee = AutoMockContainer.Create(); + + var transaction = new EnrollmentTransaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ECDH02 + } + } + }; + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithInputsWithSamePrevHashAndPrevIndex() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + } + } + }; + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithDoubleSpending() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(true); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithStrangeAssetId() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => null); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithKnownAssetIdButNotGeverningAndNotUtility() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.DutyFlag + }); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithOutputValueDivisibleByAssetRule() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero, + Value = Fixed8.MaxValue + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithoutReferences() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero, + Value = Fixed8.One + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => null); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithMoreThanOneReferenceAmountGreaterThanZero() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero, + Value = Fixed8.One + } + } + }; + + var transactionOfPreviousHash = new Transaction + { + Outputs = new [] + { + new TransactionOutput(), // it's not using the first because PrevIndex is 1 + new TransactionOutput + { + AssetId = UInt256.Parse("1a259dba256600620c6c91094f3a300b30f0cbaecee19c6114deffd3288957d7"), + Value = Fixed8.One + }, + new TransactionOutput + { + AssetId = UInt256.Parse("d4dab99ed65c3655a9619b215ab1988561b706b6e5196b6e0ada916aa6601622"), + Value = Fixed8.One + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => transactionOfPreviousHash); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithOnlyOneReferenceAmountGreaterThanZeroButItsNotUtilityToken() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero, + Value = Fixed8.One + } + } + }; + + var transactionOfPreviousHash = new Transaction + { + Outputs = new [] + { + new TransactionOutput(), // it's not using the first because PrevIndex is 1 + new TransactionOutput + { + AssetId = UInt256.Parse("1a259dba256600620c6c91094f3a300b30f0cbaecee19c6114deffd3288957d7"), + Value = Fixed8.One + }, + new TransactionOutput + { + AssetId = UInt256.Parse("1a259dba256600620c6c91094f3a300b30f0cbaecee19c6114deffd3288957d7"), + Value = Fixed8.One + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => transactionOfPreviousHash); + + var transactionContextMock = AutoMockContainer.GetMock(); + + transactionContextMock.SetupGet(x => x.UtilityTokenHash) + .Returns(UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7")); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithReferenceAmountZeroAndExistingSystemFee() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero, + Value = Fixed8.One + } + } + }; + + var transactionOfPreviousHash = new Transaction + { + Outputs = new [] + { + new TransactionOutput(), // it's not using the first because PrevIndex is 1 + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = Fixed8.Zero + }, + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = Fixed8.Zero + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => transactionOfPreviousHash); + + var transactionContextMock = AutoMockContainer.GetMock(); + + transactionContextMock.SetupGet(x => x.UtilityTokenHash) + .Returns(UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7")); + + transactionContextMock.Setup(x => x.GetSystemFee(It.IsAny())) + .Returns(Fixed8.One); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WithReferenceAmountLessThanSystemFee() + { + var testee = AutoMockContainer.Create(); + + var transaction = new Transaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero, + Value = Fixed8.One + } + } + }; + + var transactionOfPreviousHash = new Transaction + { + Outputs = new [] + { + new TransactionOutput(), // it's not using the first because PrevIndex is 1 + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = Fixed8.One + }, + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = Fixed8.One + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => transactionOfPreviousHash); + + var transactionContextMock = AutoMockContainer.GetMock(); + + transactionContextMock.SetupGet(x => x.UtilityTokenHash) + .Returns(UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7")); + + transactionContextMock.Setup(x => x.GetSystemFee(It.IsAny())) + .Returns(new Fixed8(300000000)); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_ClaimTransacWithNegativeResultOfUtilityToken() + { + var testee = AutoMockContainer.Create(); + + var transaction = new ClaimTransaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero, + Value = Fixed8.One + } + } + }; + + var transactionOfPreviousHash = new Transaction + { + Outputs = new [] + { + new TransactionOutput(), // it's not using the first because PrevIndex is 1 + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = new Fixed8(-5) + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => transactionOfPreviousHash); + + var transactionContextMock = AutoMockContainer.GetMock(); + + transactionContextMock.SetupGet(x => x.UtilityTokenHash) + .Returns(UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7")); + + transactionContextMock.Setup(x => x.GetSystemFee(It.IsAny())) + .Returns(Fixed8.Zero); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_NotMinerTransacWithNegativeResults() + { + var testee = AutoMockContainer.Create(); + + var transaction = new EnrollmentTransaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Zero, + Value = Fixed8.One + } + } + }; + + var transactionOfPreviousHash = new Transaction + { + Outputs = new [] + { + new TransactionOutput(), // it's not using the first because PrevIndex is 1 + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = Fixed8.One + }, + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = Fixed8.One + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => transactionOfPreviousHash); + + var transactionContextMock = AutoMockContainer.GetMock(); + + transactionContextMock.SetupGet(x => x.UtilityTokenHash) + .Returns(UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7")); + + transactionContextMock.Setup(x => x.GetSystemFee(It.IsAny())) + .Returns(new Fixed8(190000000)); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_WitnessVerifiedWrong() + { + var testee = AutoMockContainer.Create(); + + var transaction = new EnrollmentTransaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Parse("1a259dba256600620c6c91094f3a300b30f0cbaecee19c6114deffd3288957d7"), + Value = new Fixed8(200000000) + } + }, + Witness = new [] + { + new Witness() + } + }; + + var transactionOfPreviousHash = new Transaction + { + Outputs = new [] + { + new TransactionOutput(), // it's not using the first because PrevIndex is 1 + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = new Fixed8(200000000) + }, + new TransactionOutput + { + AssetId = UInt256.Parse("1a259dba256600620c6c91094f3a300b30f0cbaecee19c6114deffd3288957d7"), + Value = new Fixed8(200000000) + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => transactionOfPreviousHash); + + var transactionContextMock = AutoMockContainer.GetMock(); + + transactionContextMock.SetupGet(x => x.UtilityTokenHash) + .Returns(UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7")); + + transactionContextMock.Setup(x => x.GetSystemFee(It.IsAny())) + .Returns(new Fixed8(190000000)); + + var witnessOperationsManagerMock = AutoMockContainer.GetMock(); + + witnessOperationsManagerMock.Setup(x => x.Verify(It.IsAny())).Returns(false); + + var result = testee.Verify(transaction); + + result.Should().BeFalse(); + } + + [TestMethod] + public void Verify_Success() + { + var testee = AutoMockContainer.Create(); + + var transaction = new EnrollmentTransaction + { + Attributes = new [] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.ContractHash + } + }, + Inputs = new[] + { + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 1 + }, + new CoinReference + { + PrevHash = UInt256.Zero, + PrevIndex = 2 + } + }, + Outputs = new[] + { + new TransactionOutput + { + AssetId = UInt256.Parse("1a259dba256600620c6c91094f3a300b30f0cbaecee19c6114deffd3288957d7"), + Value = new Fixed8(200000000) + } + }, + Witness = new [] + { + new Witness() + } + }; + + var transactionOfPreviousHash = new Transaction + { + Outputs = new [] + { + new TransactionOutput(), // it's not using the first because PrevIndex is 1 + new TransactionOutput + { + AssetId = UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"), + Value = new Fixed8(200000000) + }, + new TransactionOutput + { + AssetId = UInt256.Parse("1a259dba256600620c6c91094f3a300b30f0cbaecee19c6114deffd3288957d7"), + Value = new Fixed8(200000000) + } + } + }; + + var blockchainMock = AutoMockContainer.GetMock(); + + blockchainMock.Setup(b => b.IsDoubleSpend(transaction)).Returns(false); + blockchainMock.Setup(b => b.GetAsset(It.IsAny())).ReturnsAsync(() => new Asset + { + AssetType = AssetType.GoverningToken + }); + blockchainMock.Setup(b => b.GetTransaction(It.IsAny())).ReturnsAsync(() => transactionOfPreviousHash); + + var transactionContextMock = AutoMockContainer.GetMock(); + + transactionContextMock.SetupGet(x => x.UtilityTokenHash) + .Returns(UInt256.Parse("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7")); + + transactionContextMock.Setup(x => x.GetSystemFee(It.IsAny())) + .Returns(new Fixed8(190000000)); + + var witnessOperationsManagerMock = AutoMockContainer.GetMock(); + + witnessOperationsManagerMock.Setup(x => x.Verify(It.IsAny())).Returns(true); + + var result = testee.Verify(transaction); + + result.Should().BeTrue(); + } + } +} \ No newline at end of file diff --git a/test/NeoSharp.Core.Test/Network/UtServer.cs b/test/NeoSharp.Core.Test/Network/UtServer.cs index 42c73751..14cca60b 100644 --- a/test/NeoSharp.Core.Test/Network/UtServer.cs +++ b/test/NeoSharp.Core.Test/Network/UtServer.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using NeoSharp.Core.Blockchain; using NeoSharp.Core.Logging; using NeoSharp.Core.Messaging; using NeoSharp.Core.Models; @@ -28,9 +27,9 @@ public void Initialize() AutoMockContainer.Register(networkConfig); - var blockchainMock = AutoMockContainer.GetMock(); + var blockchainContextMock = AutoMockContainer.GetMock(); - blockchainMock + blockchainContextMock .SetupGet(x => x.CurrentBlock) .Returns(new Block()); } diff --git a/test/NeoSharp.Core.Test/Serializers/UtBinarySerializerRaw.cs b/test/NeoSharp.Core.Test/Serializers/UtBinarySerializerRaw.cs index fdfa3c5f..a757af7b 100644 --- a/test/NeoSharp.Core.Test/Serializers/UtBinarySerializerRaw.cs +++ b/test/NeoSharp.Core.Test/Serializers/UtBinarySerializerRaw.cs @@ -77,7 +77,7 @@ public void SerializeDeserialize_Block() // MainNet - Block 1 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var blockOperationsManager = new BlockOperationsManager(Crypto.Default, BinarySerializer.Default, transactionOperationsManager, witnessOperationsManager); var blockHeaderOperationsManager = new BlockHeaderOperationsManager(Crypto.Default, BinarySerializer.Default, witnessOperationsManager); @@ -130,7 +130,7 @@ public void SerializeDeserialize_ClaimTransaction() // Mainnet Block=4275 / Tx=1 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "020001fda149910702cc19ed967c32f883a322f2e1713790c1398f538a42e489d485ee0000000001e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c60c074110000000000f41cdd4b7ec41847443fa36bf8dde0009d7ecebc01414019fcb645e67b870a657fe028bcb057f866347d211dc26a25fe0570250f41d0c881113e1820ac55a029e6fc5acab80587f9bebf8b84dbd4503ba816c417b8bf522321039f07df7861c216de3b78c647b77f8b01404b400a437302b651cdf206ec1af626ac".HexToBytes(); var tx = (ClaimTransaction)_deserializer.Deserialize(data); @@ -167,7 +167,7 @@ public void SerializeDeserialize_ContractTransaction() // Mainnet Block=47320 / Tx=1 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "80000730cf62fd54fc761f291d07d68088dd81b8b35a7c444f3af8acd78a3ad4ff75d16330aac6d49da8f63cf6442c5f707317bc3e7490029af1a75b83adc0ec3b1b3e1f0f30febc956626564e8318c1f6c11cb4e36d4ded9af1be07e25b40af39d73e4b3dc630ce2e790a02d3794e60109450943358d280389e9cdba1d09f6c105d136f38e731303329124a4a2ea122fa14dbfee41b0fae43a35b29eed33ac81c699202018dfe1530509da7d029445f07d8218fcb73a0cff2acaf76659d1f5eda826b9e896eba991030c214154a649ce8ac5ee97f3c170b6574c122731f757f2a425e5eaeab62d66586012346ed8739bb9d76afb4df8254dc237eff14013041ed694c7dab2e76753d319f0000019b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50080e03779c311005fa99d93303775fe50ca119c327759313eccfa1c01fd0401403d2ccc242d953c3b312f37b1b3aaa21a372cbb7adc1efcfc8e07f3704caa0e82aecbff5f28f17935b6432a571754060881d221a6069270c2e532f58f68248aea408cecfdd1639cae103fcf853bdf44600a6617592928fba26fa9301a222a9b4a384751453c793c2c99460a0e6e324f340abb54daf229b807cf4c8a634e5a4a1f574078891ade2cf73114de7e47b454cb88c71cca614162a7728df5f2511fd20e809ed12827139f6efae0d152cfa411d3e072f63f27f2cef4ee698327f600cc4281ff4056d91a17c56287aba509877eedc2e0541370880fb9bd4cb24a9fc754442048c29975018fbe5d16f27eeb47ca7d17d53d70fbefb8fd5c8144a82c3b72e6ca190cf1542102486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a7021024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d2102aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e2103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c2103b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a2102ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba5542102df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e89509357ae".HexToBytes(); var tx = (ContractTransaction)_deserializer.Deserialize(data); @@ -216,7 +216,7 @@ public void SerializeDeserialize_IssueTransaction() // Mainnet Block=12285 / Tx=3 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "010000017ded1c83bd63e8871c8c2ad57607fe1423e8796606f2f5c2fe25be3f27f89a430000037ded1c83bd63e8871c8c2ad57607fe1423e8796606f2f5c2fe25be3f27f89a43001f8ed117000000f41cdd4b7ec41847443fa36bf8dde0009d7ecebc7ded1c83bd63e8871c8c2ad57607fe1423e8796606f2f5c2fe25be3f27f89a4300e1f5050000000055d6bc2c5a139c894df2344e03d1d2e1fbb7b609e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6040469af32a020000f41cdd4b7ec41847443fa36bf8dde0009d7ecebc014140420d9cdc020c525f95ae8464f7c51d0b84ee820e0073536a658f35428bd44e1941f4b1697a27cbdf3975da3366db6d3e6ec8e4aef3c50eff376a330bf728b5b42321039f07df7861c216de3b78c647b77f8b01404b400a437302b651cdf206ec1af626ac".HexToBytes(); var tx = (IssueTransaction)_deserializer.Deserialize(data); @@ -259,7 +259,7 @@ public void SerializeDeserialize_MinerTransaction() // Mainnet Block=1 / tx=0 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "00004490d0bb00000000".HexToBytes(); var tx = (MinerTransaction)_deserializer.Deserialize(data); @@ -283,7 +283,7 @@ public void SerializeDeserialize_InvocationTransaction() // Mainnet Block=2421128 / Tx=7 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "d1015e0800e1f50500000000209b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5141e542e30389997d4c076ed65d0a7438719969cd653c1076465706f73697467bd097b2fcf70e1fd30a5c3ef51e662feeafeba0100000000000000000001a50be4db475e02e665229d22e82d8820e5bf8b4022c60a5806d9f1c801672cb10100019b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500e1f50500000000bd097b2fcf70e1fd30a5c3ef51e662feeafeba010141409d689aa663e04da2b74d1eba6608e4a3bacdd416a68b0102df7072e25263b63a7bfd1de1d2d3c951efa3c10c456ab41f6e3a6edaa021a309c6e31e12604132922321021958d772f0cb49220752c74c8ff6e873b8b3f69905d32c2d688cfae570fb98e0ac".HexToBytes(); var tx = (InvocationTransaction)_deserializer.Deserialize(data); @@ -322,7 +322,7 @@ public void SerializeDeserialize_RegisterTransaction() // Mainnet Block=4329 / Tx=1 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "400060335b7b226c616e67223a227a682d434e222c226e616d65223a2248656c6c6f20416e74536861726573204d61696e6e6574227d5d000084d71700000008039f07df7861c216de3b78c647b77f8b01404b400a437302b651cdf206ec1af626f41cdd4b7ec41847443fa36bf8dde0009d7ecebc0001b3ba761da52f1f5c7ce0e069707a3235613e77263b9da5dcff0737f2d09ea1f5000001e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6040bad59736020000f41cdd4b7ec41847443fa36bf8dde0009d7ecebc0141403af6b2ad6f7630f81eaaff485073c0fe4f337102d1ecf0a48ed9bcfbd4a4bbeb5d7ae26f7dd5e0e04527b313187dfe6a6a0cd7f85fd0ce431f609acce1d34aff2321039f07df7861c216de3b78c647b77f8b01404b400a437302b651cdf206ec1af626ac".HexToBytes(); #pragma warning disable CS0612 // Type or member is obsolete @@ -367,7 +367,7 @@ public void SerializeDeserialize_StateTransaction() // Mainnet Block=2394986 / Tx=6 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "9000014821025bdf3f181f53e9696227843950deb72dcd374ded17c057159513c3d0abe20b640a52656769737465726564010100015a8e6d99a868ae249878516ac521441b3f5098221ce15bcdd712efb58dda494900000001414098910b485b34a52340ac3baab13a63695b5ca44538c968ca6f2aa540654e8394ee08cc7a312144f794e780f56510f5f581e1df41859813d4bb3746b02fab15bb2321025bdf3f181f53e9696227843950deb72dcd374ded17c057159513c3d0abe20b64ac".HexToBytes(); var tx = (StateTransaction)_deserializer.Deserialize(data); @@ -406,7 +406,7 @@ public void SerializeDeserialize_PublishTransaction() // Mainnet Block=917083 / Tx=1 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "d000fd8f09746b4c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c04000000004c040000000061744c0403000000936c766b9479744c0406000000936c766b9479617cac744c0406000000948c6c766b947275744c0406000000948c6c766b9479641b004c0401000000744c0407000000948c6c766b94727562b207744c0400000000936c766b9479744c0406000000936c766b9479617cac4c04000000009c744c0408000000948c6c766b947275744c0408000000948c6c766b9479641b004c0400000000744c0407000000948c6c766b947275625607744c0404000000936c766b9479744c0409000000948c6c766b947275744c0409000000948c6c766b947964400061744c0401000000936c766b9479744c0400000000948c6c766b947275744c0402000000936c766b9479744c0401000000948c6c766b94727561623d0061744c0402000000936c766b9479744c0400000000948c6c766b947275744c0401000000936c766b9479744c0401000000948c6c766b947275614c0400000000744c0402000000948c6c766b9472754c0400000000744c0403000000948c6c766b94727561682953797374656d2e457865637574696f6e456e67696e652e476574536372697074436f6e7461696e6572616823416e745368617265732e5472616e73616374696f6e2e4765745265666572656e636573744c0404000000948c6c766b94727561744c0404000000948c6c766b9479744c040a000000948c6c766b9472754c0400000000744c040b000000948c6c766b947275629501744c040a000000948c6c766b9479744c040b000000948c6c766b9479c3744c040c000000948c6c766b94727561744c040c000000948c6c766b947961681e416e745368617265732e4f75747075742e4765745363726970744861736861682953797374656d2e457865637574696f6e456e67696e652e476574456e7472795363726970744861736887744c040d000000948c6c766b947275744c040d000000948c6c766b947964c70061744c040c000000948c6c766b947961681b416e745368617265732e4f75747075742e47657441737365744964744c0400000000948c6c766b9479874c04000000009c744c040e000000948c6c766b947275744c040e000000948c6c766b9479641b004c0400000000744c0407000000948c6c766b94727562cd04744c0402000000948c6c766b9479744c040c000000948c6c766b9479616819416e745368617265732e4f75747075742e47657456616c756593744c0402000000948c6c766b9472756161744c040b000000948c6c766b94794c040100000093744c040b000000948c6c766b947275744c040b000000948c6c766b9479744c040a000000948c6c766b9479c09f6350fe61682953797374656d2e457865637574696f6e456e67696e652e476574536372697074436f6e7461696e6572616820416e745368617265732e5472616e73616374696f6e2e4765744f757470757473744c0405000000948c6c766b94727561744c0405000000948c6c766b9479744c040f000000948c6c766b9472754c0400000000744c0410000000948c6c766b947275621c02744c040f000000948c6c766b9479744c0410000000948c6c766b9479c3744c0411000000948c6c766b94727561744c0411000000948c6c766b947961681e416e745368617265732e4f75747075742e4765745363726970744861736861682953797374656d2e457865637574696f6e456e67696e652e476574456e7472795363726970744861736887744c0412000000948c6c766b947275744c0412000000948c6c766b9479644e0161744c0411000000948c6c766b947961681b416e745368617265732e4f75747075742e47657441737365744964744c0400000000948c6c766b947987744c0413000000948c6c766b947275744c0413000000948c6c766b9479644e00744c0402000000948c6c766b9479744c0411000000948c6c766b9479616819416e745368617265732e4f75747075742e47657456616c756594744c0402000000948c6c766b94727562a600744c0411000000948c6c766b947961681b416e745368617265732e4f75747075742e47657441737365744964744c0401000000948c6c766b947987744c0414000000948c6c766b947275744c0414000000948c6c766b9479644b00744c0403000000948c6c766b9479744c0411000000948c6c766b9479616819416e745368617265732e4f75747075742e47657456616c756593744c0403000000948c6c766b9472756161744c0410000000948c6c766b94794c040100000093744c0410000000948c6c766b947275744c0410000000948c6c766b9479744c040f000000948c6c766b9479c09f63c9fd744c0402000000948c6c766b94794c0400000000a1744c0415000000948c6c766b947275744c0415000000948c6c766b9479641b004c0401000000744c0407000000948c6c766b947275622301744c0404000000936c766b9479744c0416000000948c6c766b947275744c0416000000948c6c766b947964720061744c0403000000948c6c766b94794c0400e1f50595744c0402000000948c6c766b9479744c0405000000936c766b9479959f744c0417000000948c6c766b947275744c0417000000948c6c766b9479641b004c0400000000744c0407000000948c6c766b947275628b0061626f0061744c0402000000948c6c766b94794c0400e1f50595744c0403000000948c6c766b9479744c0405000000936c766b947995a0744c0418000000948c6c766b947275744c0418000000948c6c766b9479641b004c0400000000744c0407000000948c6c766b947275621c00614c0401000000744c0407000000948c6c766b947275620300744c0407000000948c6c766b947961748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d748c6c766b946d746c768c6b946d746c768c6b946d746c768c6b946d746c768c6b946d746c768c6b946d746c768c6b946d746c768c6b946d6c75660703040403010200010e4167656e6379436f6e74726163740e322e302e312d70726576696577310a4572696b205a68616e67126572696b40616e747368617265732e6f7267134167656e637920436f6e747261637420322e3000017d87a0660bbc929d5eccde32787fcfc790c719cff5dd848c48a2a25eff62bf68000001e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6000e1f50500000000ae0211ab29b392cfc71f6bc2a44358634bb22a2e01414086270040b5378a1b9afb5387e705d381afd19f08ee9dd3d5a3ec164132c5085e2e7298a172fabfae827044acc81393e8ee3f3eae514bbb523c6dc2db0b03c456232102abab730e3b83ae352a1d5210d8c4dac9cf2cacc6baf479709d7b989c2151b867ac".HexToBytes(); #pragma warning disable CS0612 // Type or member is obsolete @@ -460,7 +460,7 @@ public void SerializeDeserialize_EnrollmentTransaction() // Mainnet Block=47293 / Tx=1 var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); var data = "200003b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c0001f2f5be8a2d2d3d62e1601646b1c8b4ab58b8ee1595caf3e4a0bbfefe029719e2000001e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c6000e1f505000000009f2d1729a79436148dc442c25f41335ef9f78bbd014140831597a1f22cba5fb4aa85ade9629a8fd18b46a05ba576a0ab71bcccb6e3fba9593555951f219baeb3368e0c2d722694455403d191d200177afb8f5ac69b5566232103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70cac".HexToBytes(); #pragma warning disable CS0612 // Type or member is obsolete diff --git a/test/NeoSharp.Core.Test/Serializers/UtBinarySerializerTx.cs b/test/NeoSharp.Core.Test/Serializers/UtBinarySerializerTx.cs index fbaa4607..a5e12774 100644 --- a/test/NeoSharp.Core.Test/Serializers/UtBinarySerializerTx.cs +++ b/test/NeoSharp.Core.Test/Serializers/UtBinarySerializerTx.cs @@ -313,7 +313,7 @@ public void SerializeDeserialize_ClaimTransaction() private void FillRandomTx(Transaction tx) { var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); tx.Attributes = RandomTransactionAtrributes().ToArray(); tx.Inputs = RandomCoinReferences(_random.Next(1, 255)).ToArray(); @@ -326,7 +326,7 @@ private void FillRandomTx(Transaction tx) void EqualTx(Transaction original, params Transaction[] copies) { var witnessOperationsManager = new WitnessOperationsManager(Crypto.Default); - var transactionOperationsManager = new TransactionOperationsManager(Crypto.Default, witnessOperationsManager); + var transactionOperationsManager = new TransactionSigner(Crypto.Default, witnessOperationsManager); foreach (var copy in copies) { diff --git a/test/NeoSharp.Core.Test/Wallet/NEP6WalletTest.cs b/test/NeoSharp.Core.Test/Wallet/NEP6WalletTest.cs index 98f5ea34..a5a4719a 100644 --- a/test/NeoSharp.Core.Test/Wallet/NEP6WalletTest.cs +++ b/test/NeoSharp.Core.Test/Wallet/NEP6WalletTest.cs @@ -518,57 +518,22 @@ public void TestImportWifEmpty() #region Check Password [TestMethod] + [ExpectedException(typeof(AccountsPasswordMismatchException))] public void TestVerifyPasswordFalse() { var mockWalletManager = GetAWalletManagerWithAnWallet(); - + mockWalletManager.CreateAndAddAccount(_defaultPassword); // Act SecureString fakeString = new SecureString(); fakeString.AppendChar('1'); - bool result = mockWalletManager.VerifyPassword(new NEP6Account(_testContract) { Key = "6PYVwbrWfiyKCFnj4EjjBESUer4hbQ48hPfn8as8ivyS3FTVVmAJomvYuv" }, fakeString); - - Assert.IsFalse(result); + mockWalletManager.CheckIfPasswordMatchesOpenWallet(fakeString); } [TestMethod] public void TestVerifyPassword() { var mockWalletManager = GetAWalletManagerWithAnWallet(); - - // Act - bool result = mockWalletManager.VerifyPassword(new NEP6Account(_testContract) { Key = "6PYVwbrWfiyKCFnj4EjjBESUer4hbQ48hPfn8as8ivyS3FTVVmAJomvYuv" }, _defaultPassword); - - Assert.IsTrue(result); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentException))] - public void TestVerifyPasswordAccountNull() - { - var mockWalletManager = GetAWalletManagerWithAnWallet(); - - // Act - mockWalletManager.VerifyPassword(null, _defaultPassword); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void TestVerifyPasswordNep2KeyNull() - { - var mockWalletManager = GetAWalletManagerWithAnWallet(); - - // Act - mockWalletManager.VerifyPassword(new NEP6Account(_testContract) { Key = null }, _defaultPassword); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void TestVerifyPasswordNep2KeyEmpty() - { - var mockWalletManager = GetAWalletManagerWithAnWallet(); - - // Act - mockWalletManager.VerifyPassword(new NEP6Account(_testContract) { Key = String.Empty }, _defaultPassword); + mockWalletManager.CheckIfPasswordMatchesOpenWallet(_defaultPassword); } [TestMethod] @@ -578,17 +543,7 @@ public void TestVerifyPasswordPasswordNull() var mockWalletManager = GetAWalletManagerWithAnWallet(); // Act - mockWalletManager.VerifyPassword(new NEP6Account(_testContract) { Key = "6PYVwbrWfiyKCFnj4EjjBESUer4hbQ48hPfn8as8ivyS3FTVVmAJomvYuv" }, null); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void TestVerifyPasswordPasswordEmpty() - { - var mockWalletManager = GetAWalletManagerWithAnWallet(); - - // Act - mockWalletManager.VerifyPassword(new NEP6Account(_testContract) { Key = "6PYVwbrWfiyKCFnj4EjjBESUer4hbQ48hPfn8as8ivyS3FTVVmAJomvYuv" }, null); + mockWalletManager.CheckIfPasswordMatchesOpenWallet(null); } #endregion