├── UbudKusCoin ├── DbFiles │ └── README.MD ├── appsettings.json ├── appsettings.Development.json ├── .env ├── env-examples │ ├── .env1 │ ├── .env3 │ ├── .env4 │ └── .env2 ├── deploy.sh ├── Facade │ ├── StakeFacade.cs │ ├── TransactionPoolFacade.cs │ ├── PeerFacade.cs │ ├── TransactionFacade.cs │ ├── AccountFacade.cs │ └── BlockFacade.cs ├── Protos │ ├── stake.proto │ ├── account.proto │ ├── peer.proto │ ├── block.proto │ └── transaction.proto ├── LICENSE ├── Grpc │ ├── StakeServiceImpl.cs │ ├── PeerServiceImpl.cs │ ├── AccountServiceImpl.cs │ ├── BlockServiceImpl.cs │ └── TransactionServiceImpl.cs ├── Services │ ├── FacadeService.cs │ ├── ServicePool.cs │ ├── WalletService.cs │ ├── DBService.cs │ └── MintingService.cs ├── UbudKusCoin.service ├── Others │ ├── Constants.cs │ └── Utils.cs ├── UbudKusCoin.csproj ├── DB │ ├── PoolTransactionsDb.cs │ ├── PeerDb.cs │ ├── AccountDb.cs │ ├── StakeDb.cs │ ├── TransactionDb.cs │ └── BlockDb.cs ├── Startup.cs ├── Program.cs └── P2P │ └── P2PService.cs ├── ConsoleWallet ├── .env ├── Program.cs ├── Protos │ ├── stake.proto │ ├── account.proto │ ├── peer.proto │ ├── block.proto │ └── transaction.proto ├── LICENSE ├── ConsoleWallet.csproj ├── Others │ └── Utils.cs ├── Wallet.cs └── ConsoleAppWallet.cs ├── .vscode ├── settings.json ├── launch.json └── tasks.json ├── .gitignore ├── BlockExplorer ├── Others │ └── Utils.cs ├── Program.cs ├── Protos │ ├── account.proto │ ├── block.proto │ └── transaction.proto ├── LICENSE ├── BlockExplorer.csproj └── BlockExplorer.cs ├── LICENSE ├── UbudKusCoin.sln └── README.md /UbudKusCoin/DbFiles/README.MD: -------------------------------------------------------------------------------- 1 | Please don't delete this folder. 2 | -------------------------------------------------------------------------------- /ConsoleWallet/.env: -------------------------------------------------------------------------------- 1 | 2 | NODE_ADDRESS = "http://127.0.0.1:5002" 3 | add="live uniform pudding know thumb hand deposit critic relief asset demand barrel" -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.classpath": true, 4 | "**/.project": true, 5 | "**/.settings": true, 6 | "**/.factorypath": true 7 | } 8 | } -------------------------------------------------------------------------------- /UbudKusCoin/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "None", 6 | "System.*": "None", 7 | "Grpc.*": "None", 8 | "Microsoft.*": "None", 9 | "Microsoft.Hosting.*": "None" 10 | } 11 | }, 12 | "AllowedHosts": "*" 13 | } 14 | -------------------------------------------------------------------------------- /UbudKusCoin/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "None", 6 | "System.*": "None", 7 | "Grpc.*": "None", 8 | "Microsoft.*": "None", 9 | "Microsoft.Hosting.*": "None" 10 | } 11 | }, 12 | "AllowedHosts": "*" 13 | } 14 | -------------------------------------------------------------------------------- /UbudKusCoin/.env: -------------------------------------------------------------------------------- 1 | 2 | #BOOTSRTAP_PEERS is same for all nodes 3 | BOOTSRTAP_PEERS="http://127.0.0.1:5002" 4 | 5 | #NODE PASSPHRASE and NODE ADDRESS is specific for each node 6 | GRPC_WEB_PORT=5001 7 | GRPC_PORT=5002 8 | NODE_ADDRESS="http://127.0.0.1:5002" 9 | 10 | NODE_PASSPHRASE="actual lucky tail message acquire alarm bomb finger route wool reward bike" 11 | -------------------------------------------------------------------------------- /UbudKusCoin/env-examples/.env1: -------------------------------------------------------------------------------- 1 | #BOOTSRTAP_PEERS is same for all nodes 2 | BOOTSRTAP_PEERS="http://127.0.0.1:5002" 3 | 4 | #NODE PASSPHRASE and NODE ADDRESS is specific for each node 5 | GRPC_WEB_PORT = 5001 6 | GRPC_PORT = 5002 7 | NODE_ADDRESS = "http://127.0.0.1:5002" 8 | NODE_PASSPHRASE="actual lucky tail message acquire alarm bomb finger route wool reward bike" 9 | -------------------------------------------------------------------------------- /UbudKusCoin/env-examples/.env3: -------------------------------------------------------------------------------- 1 | #BOOTSRTAP_PEERS is same for all nodes 2 | BOOTSRTAP_PEERS="http://127.0.0.1:5002" 3 | 4 | #NODE PASSPHRASE and NODE ADDRESS is specific for each node 5 | GRPC_WEB_PORT=5005 6 | GRPC_PORT=5006 7 | NODE_ADDRESS="http://127.0.0.1:5006" 8 | NODE_PASSPHRASE="transfer divorce liberty laptop harbor cotton hollow drop record deal pill charge" 9 | -------------------------------------------------------------------------------- /UbudKusCoin/env-examples/.env4: -------------------------------------------------------------------------------- 1 | #BOOTSRTAP_PEERS is same for all nodes 2 | BOOTSRTAP_PEERS="http://127.0.0.1:5002" 3 | 4 | #NODE PASSPHRASE and NODE ADDRESS is specific for each node 5 | GRPC_WEB_PORT=5007 6 | GRPC_PORT=5008 7 | NODE_ADDRESS="http://127.0.0.1:5008" 8 | NODE_PASSPHRASE="elite mosquito enrich remain story indoor mutual elite polar juice enter craft" 9 | -------------------------------------------------------------------------------- /UbudKusCoin/env-examples/.env2: -------------------------------------------------------------------------------- 1 | #BOOTSRTAP_PEERS is same for all nodes 2 | BOOTSRTAP_PEERS="http://127.0.0.1:5002" 3 | 4 | #NODE PASSPHRASE and NODE ADDRESS is specific for each node 5 | GRPC_WEB_PORT=5003 6 | GRPC_PORT=5004 7 | NODE_ADDRESS="http://127.0.0.1:5004" 8 | NODE_PASSPHRASE="owner elevator visual public loyal actual outside trumpet sugar drama impact royal" 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /UbudKusCoin/obj 2 | /UbudKusCoin/*.zip 3 | /UbudKusCoin/bin 4 | /UbudKusCoin/DbFiles/*.db 5 | /UbudKusCoin/publish-linux 6 | 7 | /BlockExplorer/obj/* 8 | /BlockExplorer/bin/ 9 | /BlockExplorer/*.db 10 | /BlockExplorer/publish-linux 11 | 12 | /ConsoleWallet/obj/* 13 | /ConsoleWallet/bin/ 14 | /ConsoleWallet/*.db 15 | /ConsoleWallet/publish-linux 16 | 17 | .vs 18 | /UnitTest/bin 19 | /UnitTest/obj 20 | 21 | /ConsoleWallet/bin 22 | /ConsoleWallet/obj 23 | 24 | /BlockExplorer/bin 25 | /BlockExplorer/obj 26 | 27 | .vs 28 | /UnitTest/bin 29 | /UnitTest/obj 30 | .history 31 | .vscode 32 | 33 | .fake 34 | .ionide 35 | -------------------------------------------------------------------------------- /BlockExplorer/Others/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UbudKusCoin.BlockExplorer.Others 4 | { 5 | public static class Utils 6 | { 7 | public static DateTime ToDateTime(long unixTime) 8 | { 9 | DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 10 | dtDateTime = dtDateTime.AddSeconds(unixTime).ToLocalTime(); 11 | return dtDateTime; 12 | } 13 | 14 | public static long GetTime() 15 | { 16 | long epochTicks = new DateTime(1970, 1, 1).Ticks; 17 | long nowTicks = DateTime.UtcNow.Ticks; 18 | return (nowTicks - epochTicks) / TimeSpan.TicksPerSecond; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /BlockExplorer/Program.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using Grpc.Net.Client; 10 | 11 | namespace UbudKusCoin.BlockExplorer 12 | { 13 | class Program 14 | { 15 | static void Main(string[] args) 16 | { 17 | var serverAddress = "http://localhost:5002"; 18 | AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); 19 | GrpcChannel channel = GrpcChannel.ForAddress(serverAddress); 20 | _ = new BlockExplorer(channel); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /UbudKusCoin/deploy.sh: -------------------------------------------------------------------------------- 1 | # rm -rf publish-linux 2 | 3 | dotnet publish -c Release -r linux-x64 -o ./publish-linux 4 | #dotnet publish -c Release -r osx-x64 -o ./publish-osx 5 | #dotnet publish -c Release -r win-x64 -o ./publish-win64 6 | 7 | # zip -r uksc.zip publish-linux 8 | 9 | mkdir -p ~/NODES 10 | mkdir -p ~/NODES/node1 11 | mkdir -p ~/NODES/node2 12 | mkdir -p ~/NODES/node3 13 | mkdir -p ~/NODES/node4 14 | 15 | rm -rf ~/NODES/node1/* 16 | rm -rf ~/NODES/node2/* 17 | rm -rf ~/NODES/node3/* 18 | rm -rf ~/NODES/node4/* 19 | 20 | cp publish-linux/* -d ~/NODES/node1 21 | cp publish-linux/* -d ~/NODES/node2 22 | cp publish-linux/* -d ~/NODES/node3 23 | cp publish-linux/* -d ~/NODES/node4 24 | 25 | cp env-examples/.env1 ~/NODES/node1/.env 26 | cp env-examples/.env2 ~/NODES/node2/.env 27 | cp env-examples/.env3 ~/NODES/node3/.env 28 | cp env-examples/.env4 ~/NODES/node4/.env 29 | 30 | -------------------------------------------------------------------------------- /ConsoleWallet/Program.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using Grpc.Net.Client; 10 | 11 | namespace UbudKusCoin.ConsoleWallet 12 | { 13 | class Program 14 | { 15 | static void Main() 16 | { 17 | DotNetEnv.Env.Load(); 18 | DotNetEnv.Env.TraversePath().Load(); 19 | 20 | var NODE_ADDRESS = DotNetEnv.Env.GetString("NODE_ADDRESS"); 21 | AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); 22 | GrpcChannel channel = GrpcChannel.ForAddress(NODE_ADDRESS); 23 | _ = new ConsoleAppWallet(channel); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /UbudKusCoin/Facade/StakeFacade.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using UbudKusCoin.Grpc; 10 | using UbudKusCoin.Services; 11 | 12 | namespace UbudKusCoin.Facade 13 | { 14 | public class StakeFacade 15 | { 16 | public StakeFacade() 17 | { 18 | Console.WriteLine("...... Stake innitialized."); 19 | } 20 | 21 | public Stake GetMaxStake() 22 | { 23 | return ServicePool.DbService.StakeDb.GetMax(); 24 | } 25 | 26 | public void AddOrUpdate(Stake stake) 27 | { 28 | ServicePool.DbService.StakeDb.AddOrUpdate(stake); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /ConsoleWallet/Protos/stake.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service StakeService { 12 | rpc Add(Stake) returns (AddStakeStatus); 13 | rpc GetRange(StakeParams) returns (StakeList); 14 | } 15 | 16 | message AddStakeStatus{ 17 | string status = 1; 18 | string message = 2; 19 | } 20 | 21 | message StakeParams{ 22 | int32 page_number = 1; 23 | int32 result_per_page = 2; 24 | } 25 | 26 | message StakeList { 27 | repeated Stake stakes = 1; 28 | } 29 | 30 | message Stake { 31 | int32 Id = 1; 32 | string address = 2; 33 | double amount = 3; 34 | int64 time_stamp = 4; 35 | } -------------------------------------------------------------------------------- /UbudKusCoin/Protos/stake.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service StakeService { 12 | rpc Add(Stake) returns (AddStakeStatus); 13 | rpc GetRange(StakeParams) returns (StakeList); 14 | } 15 | 16 | message AddStakeStatus{ 17 | string status = 1; 18 | string message = 2; 19 | } 20 | 21 | message StakeParams{ 22 | int32 page_number = 1; 23 | int32 result_per_page = 2; 24 | } 25 | 26 | message StakeList { 27 | repeated Stake stakes = 1; 28 | } 29 | 30 | message Stake { 31 | int32 Id = 1; 32 | string address = 2; 33 | double amount = 3; 34 | int64 time_stamp = 4; 35 | } -------------------------------------------------------------------------------- /UbudKusCoin/Facade/TransactionPoolFacade.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using UbudKusCoin.Grpc; 10 | using UbudKusCoin.Services; 11 | 12 | namespace UbudKusCoin.Facade 13 | { 14 | public class TransactionPoolFacade 15 | { 16 | public TransactionPoolFacade() 17 | { 18 | Console.WriteLine("...... Transaction pool innitialized"); 19 | } 20 | 21 | public bool TransactionExists(Transaction txn) 22 | { 23 | var transaction = ServicePool.DbService.PoolTransactionsDb.GetByHash(txn.Hash); 24 | if (transaction is null) 25 | { 26 | return false; 27 | } 28 | 29 | return false; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /BlockExplorer/Protos/account.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service AccountService { 12 | rpc Add(Account) returns (Account); 13 | rpc Update(Account) returns (Account); 14 | rpc GetByPubKey(Account) returns (Account); 15 | rpc GetByAddress(Account) returns (Account); 16 | rpc GetRange(AccountParams) returns (AccountList); 17 | } 18 | 19 | message AccountParams{ 20 | int32 page_number = 1; 21 | int32 result_per_page = 2; 22 | } 23 | 24 | message AccountList { 25 | repeated Account accounts = 1; 26 | } 27 | 28 | message Account { 29 | int64 Id = 1; 30 | string address = 2; 31 | string pub_key = 3; 32 | double balance = 4; 33 | int64 txn_count = 5; 34 | int64 created = 6; 35 | int64 updated = 7; 36 | } -------------------------------------------------------------------------------- /ConsoleWallet/Protos/account.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service AccountService { 12 | rpc Add(Account) returns (Account); 13 | rpc Update(Account) returns (Account); 14 | rpc GetByPubKey(Account) returns (Account); 15 | rpc GetByAddress(Account) returns (Account); 16 | rpc GetRange(AccountParams) returns (AccountList); 17 | } 18 | 19 | message AccountParams{ 20 | int32 page_number = 1; 21 | int32 result_per_page = 2; 22 | } 23 | 24 | message AccountList { 25 | repeated Account accounts = 1; 26 | } 27 | 28 | message Account { 29 | int64 Id = 1; 30 | string address = 2; 31 | string pub_key = 3; 32 | double balance = 4; 33 | int64 txn_count = 5; 34 | int64 created = 6; 35 | int64 updated = 7; 36 | } -------------------------------------------------------------------------------- /UbudKusCoin/Protos/account.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service AccountService { 12 | rpc Add(Account) returns (Account); 13 | rpc Update(Account) returns (Account); 14 | rpc GetByPubKey(Account) returns (Account); 15 | rpc GetByAddress(Account) returns (Account); 16 | rpc GetRange(AccountParams) returns (AccountList); 17 | } 18 | 19 | 20 | message AccountParams{ 21 | int32 page_number = 1; 22 | int32 result_per_page = 2; 23 | } 24 | 25 | message AccountList { 26 | repeated Account accounts = 1; 27 | } 28 | 29 | message Account { 30 | int64 Id = 1; 31 | string address = 2; 32 | string pub_key = 3; 33 | double balance = 4; 34 | int64 txn_count = 5; 35 | int64 created = 6; 36 | int64 updated = 7; 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 I Putu Kusuma Negara, ST, MKOM. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /UbudKusCoin/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 I Putu Kusuma Negara, ST, MKOM. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /BlockExplorer/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 I Putu Kusuma Negara, ST, MKOM. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ConsoleWallet/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 I Putu Kusuma Negara, ST, MKOM. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/UbudKusCoin/bin/Debug/netcoreapp2.2/UbudKusCoin.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/UbudKusCoin", 16 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console 17 | "console": "internalConsole", 18 | "stopAtEntry": false 19 | }, 20 | { 21 | "name": ".NET Core Attach", 22 | "type": "coreclr", 23 | "request": "attach", 24 | "processId": "${command:pickProcess}" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /BlockExplorer/BlockExplorer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | all 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ConsoleWallet/Protos/peer.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service PeerService { 12 | rpc Add(Peer) returns (AddPeerReply); 13 | rpc GetAll(PeerPaging) returns (PeerList); 14 | rpc GetNodeState(NodeParam) returns (NodeState); 15 | } 16 | 17 | message NodeParam{ 18 | string nodeIpAddress = 1; 19 | } 20 | 21 | message AddPeerReply{ 22 | string status = 1; 23 | string message = 2; 24 | } 25 | 26 | message PeerPaging{ 27 | int32 page_number = 1; 28 | int32 result_per_page = 2; 29 | } 30 | 31 | message PeerList { 32 | repeated Peer peers = 1; 33 | } 34 | 35 | message Peer { 36 | int32 Id = 1; 37 | string address = 2; 38 | int64 last_reach = 3; 39 | bool is_bootstrap = 4; 40 | bool is_canreach = 5; 41 | int64 time_stamp = 6; 42 | } 43 | 44 | message NodeState { 45 | string hash = 1; 46 | int64 height = 2; 47 | repeated Peer known_peers = 3; 48 | string address = 4; 49 | int32 version = 5; 50 | } -------------------------------------------------------------------------------- /UbudKusCoin/Protos/peer.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service PeerService { 12 | rpc Add(Peer) returns (AddPeerReply); 13 | rpc GetAll(PeerPaging) returns (PeerList); 14 | rpc GetNodeState(NodeParam) returns (NodeState); 15 | } 16 | 17 | message NodeParam{ 18 | string nodeIpAddress = 1; 19 | } 20 | 21 | message AddPeerReply{ 22 | string status = 1; 23 | string message = 2; 24 | } 25 | 26 | message PeerPaging{ 27 | int32 page_number = 1; 28 | int32 result_per_page = 2; 29 | } 30 | 31 | message PeerList { 32 | repeated Peer peers = 1; 33 | } 34 | 35 | message Peer { 36 | int32 Id = 1; 37 | string address = 2; 38 | int64 last_reach = 3; 39 | bool is_bootstrap = 4; 40 | bool is_canreach = 5; 41 | int64 time_stamp = 6; 42 | } 43 | 44 | message NodeState { 45 | string hash = 1; 46 | int64 height = 2; 47 | repeated Peer known_peers = 3; 48 | string address = 4; 49 | int32 version = 5; 50 | } -------------------------------------------------------------------------------- /ConsoleWallet/ConsoleWallet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | all 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /UbudKusCoin/Grpc/StakeServiceImpl.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using Grpc.Core; 9 | using System.Threading.Tasks; 10 | using UbudKusCoin.Services; 11 | 12 | namespace UbudKusCoin.Grpc 13 | { 14 | public class StakeServiceImpl : StakeService.StakeServiceBase 15 | { 16 | public override Task Add(Stake req, ServerCallContext context) 17 | { 18 | ServicePool.DbService.StakeDb.AddOrUpdate(req); 19 | return Task.FromResult(new AddStakeStatus 20 | { 21 | Message = "Stake successfully added", 22 | Status = Others.Constants.TXN_STATUS_SUCCESS, 23 | }); 24 | } 25 | 26 | public override Task GetRange(StakeParams req, ServerCallContext context) 27 | { 28 | var response = new StakeList(); 29 | var stakes = ServicePool.DbService.StakeDb.GetAll(); 30 | response.Stakes.AddRange(stakes.FindAll()); 31 | return Task.FromResult(response); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /UbudKusCoin/Grpc/PeerServiceImpl.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | using Grpc.Core; 8 | using UbudKusCoin.Services; 9 | using System.Threading.Tasks; 10 | 11 | namespace UbudKusCoin.Grpc 12 | { 13 | public class PeerServiceImpl : PeerService.PeerServiceBase 14 | { 15 | public override Task Add(Peer request, ServerCallContext context) 16 | { 17 | var response = new AddPeerReply(); 18 | return Task.FromResult(response); 19 | } 20 | 21 | public override Task GetNodeState(NodeParam request, ServerCallContext context) 22 | { 23 | ServicePool.FacadeService.Peer.Add(new Peer 24 | { 25 | Address = request.NodeIpAddress, 26 | IsBootstrap = false, 27 | IsCanreach = true, 28 | LastReach = Others.UkcUtils.GetTime(), 29 | TimeStamp = Others.UkcUtils.GetTime() 30 | }); 31 | 32 | var nodeState = ServicePool.FacadeService.Peer.GetNodeState(); 33 | return Task.FromResult(nodeState); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /UbudKusCoin/Services/FacadeService.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using UbudKusCoin.Facade; 10 | 11 | namespace UbudKusCoin.Services 12 | { 13 | public class FacadeService 14 | { 15 | public PeerFacade Peer { set; get; } 16 | public AccountFacade Account { set; get; } 17 | public BlockFacade Block { set; get; } 18 | public TransactionFacade Transaction { set; get; } 19 | public TransactionPoolFacade TransactionPool { set; get; } 20 | public StakeFacade Stake { set; get; } 21 | 22 | public FacadeService() 23 | { 24 | } 25 | 26 | public void start() 27 | { 28 | Console.WriteLine("... Facade service is starting"); 29 | Peer = new PeerFacade(); 30 | Stake = new StakeFacade(); 31 | Account = new AccountFacade(); 32 | TransactionPool = new TransactionPoolFacade(); 33 | Transaction = new TransactionFacade(); 34 | Block = new BlockFacade(); 35 | Console.WriteLine("...... Facade service is ready"); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /UbudKusCoin/UbudKusCoin.service: -------------------------------------------------------------------------------- 1 | #EXAMPLE OF SERVICE FOR LINUX 2 | 3 | [Unit] 4 | Description=UbudKusCoin Service 5 | 6 | [Service] 7 | Type=notify 8 | 9 | # will set the Current Working Directory (CWD). Worker service will have issues without this setting 10 | WorkingDirectory=/home/ubuntu/ukc 11 | 12 | # systemd will run this executable to start the service 13 | ExecStart=/home/ubuntu/ukc/UbudKusCoin 14 | 15 | # to query logs using journalctl, set a logical name here 16 | SyslogIdentifier=UbudKusCoin 17 | 18 | # Use your username to keep things simple. 19 | # If you pick a different user, make sure dotnet and all permissions are set correctly to run the app 20 | # To update permissions, use 'chown yourusername -R /home/ubuntu/ukc' to take ownership of the folder and files, 21 | # Use 'chmod +x /home/ubuntu/ukc/UbudKusCoin' to allow execution of the executable file 22 | User=ubuntu 23 | 24 | # ensure the service restarts after crashing 25 | Restart=always 26 | # amount of time to wait before restarting the service 27 | RestartSec=5 28 | 29 | # This environment variable is necessary when dotnet isn't loaded for the specified user. 30 | # To figure out this value, run 'env | grep DOTNET_ROOT' when dotnet has been loaded into your shell. 31 | # Environment=DOTNET_ROOT=/opt/rh/rh-dotnet31/root/usr/lib64/dotnet 32 | 33 | [Install] 34 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/UbudKusCoin/UbudKusCoin.csproj", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | }, 16 | { 17 | "label": "publish", 18 | "command": "dotnet", 19 | "type": "process", 20 | "args": [ 21 | "publish", 22 | "${workspaceFolder}/UbudKusCoin/UbudKusCoin.csproj", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "problemMatcher": "$msCompile" 27 | }, 28 | { 29 | "label": "watch", 30 | "command": "dotnet", 31 | "type": "process", 32 | "args": [ 33 | "watch", 34 | "run", 35 | "${workspaceFolder}/UbudKusCoin/UbudKusCoin.csproj", 36 | "/property:GenerateFullPaths=true", 37 | "/consoleloggerparameters:NoSummary" 38 | ], 39 | "problemMatcher": "$msCompile" 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /UbudKusCoin/Grpc/AccountServiceImpl.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | 9 | using Grpc.Core; 10 | using System.Threading.Tasks; 11 | using UbudKusCoin.Services; 12 | 13 | namespace UbudKusCoin.Grpc 14 | { 15 | public class AccountServiceImpl : AccountService.AccountServiceBase 16 | { 17 | public override Task GetRange(AccountParams request, ServerCallContext context) 18 | { 19 | var accounts = ServicePool.DbService.AccountDb.GetRange(request.PageNumber, request.ResultPerPage); 20 | var response = new AccountList(); 21 | response.Accounts.AddRange(accounts); 22 | return Task.FromResult(response); 23 | } 24 | 25 | public override Task GetByAddress(Account request, ServerCallContext context) 26 | { 27 | var account = ServicePool.DbService.AccountDb.GetByAddress(request.Address); 28 | return Task.FromResult(account); 29 | } 30 | 31 | public override Task GetByPubKey(Account request, ServerCallContext context) 32 | { 33 | var account = ServicePool.DbService.AccountDb.GetByPubKey(request.PubKey); 34 | return Task.FromResult(account); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /BlockExplorer/Protos/block.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service BlockService { 12 | rpc Add(Block)returns (AddBlockStatus); 13 | rpc GetRemains(StartingParam)returns (BlockList); 14 | rpc GetRange(BlockParams) returns (BlockList); 15 | rpc GetByHeight(Block) returns (Block); 16 | rpc GetByHash(Block) returns (Block); 17 | rpc GetFirst(EmptyRequest) returns (Block); 18 | rpc GetLast(EmptyRequest) returns (Block); 19 | } 20 | 21 | message EmptyRequest{ 22 | } 23 | 24 | message AddBlockStatus{ 25 | string status = 1; 26 | string message = 2; 27 | } 28 | 29 | message StartingParam{ 30 | int64 height = 1; 31 | } 32 | 33 | message BlockParams{ 34 | int32 page_number = 1; 35 | int32 result_per_page = 2; 36 | } 37 | 38 | message BlockList { 39 | repeated Block blocks = 1; 40 | } 41 | 42 | message Block { 43 | int32 version = 1; 44 | int64 height = 2; 45 | int64 time_stamp = 3; 46 | string prev_hash = 4; 47 | string hash = 5; 48 | string transactions = 6; 49 | string validator = 7; 50 | double validator_balance = 8; 51 | string merkle_root = 9; 52 | int32 num_of_tx = 10; 53 | double total_amount = 11; 54 | double total_reward = 12; 55 | int32 difficulty = 13; 56 | int32 nonce = 14; 57 | int32 size = 15; 58 | int32 build_time = 16; 59 | } -------------------------------------------------------------------------------- /ConsoleWallet/Protos/block.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service BlockService { 12 | rpc Add(Block)returns (AddBlockStatus); 13 | rpc GetRemains(StartingParam)returns (BlockList); 14 | rpc GetRange(BlockParams) returns (BlockList); 15 | rpc GetByHeight(Block) returns (Block); 16 | rpc GetByHash(Block) returns (Block); 17 | rpc GetFirst(EmptyRequest) returns (Block); 18 | rpc GetLast(EmptyRequest) returns (Block); 19 | } 20 | 21 | message EmptyRequest{ 22 | } 23 | 24 | message AddBlockStatus{ 25 | string status = 1; 26 | string message = 2; 27 | } 28 | 29 | message StartingParam{ 30 | int64 height = 1; 31 | } 32 | 33 | message BlockParams{ 34 | int32 page_number = 1; 35 | int32 result_per_page = 2; 36 | } 37 | 38 | message BlockList { 39 | repeated Block blocks = 1; 40 | } 41 | 42 | message Block { 43 | int32 version = 1; 44 | int64 height = 2; 45 | int64 time_stamp = 3; 46 | string prev_hash = 4; 47 | string hash = 5; 48 | string transactions = 6; 49 | string validator = 7; 50 | double validator_balance = 8; 51 | string merkle_root = 9; 52 | int32 num_of_tx = 10; 53 | double total_amount = 11; 54 | double total_reward = 12; 55 | int32 difficulty = 13; 56 | int32 nonce = 14; 57 | int32 size = 15; 58 | int32 build_time = 16; 59 | string signature = 17; 60 | } -------------------------------------------------------------------------------- /UbudKusCoin/Protos/block.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service BlockService { 12 | rpc Add(Block)returns (AddBlockStatus); 13 | rpc GetRemains(StartingParam)returns (BlockList); 14 | rpc GetRange(BlockParams) returns (BlockList); 15 | rpc GetByHeight(Block) returns (Block); 16 | rpc GetByHash(Block) returns (Block); 17 | rpc GetFirst(EmptyRequest) returns (Block); 18 | rpc GetLast(EmptyRequest) returns (Block); 19 | } 20 | 21 | message EmptyRequest{ 22 | } 23 | 24 | message AddBlockStatus{ 25 | string status = 1; 26 | string message = 2; 27 | } 28 | 29 | message StartingParam{ 30 | int64 height = 1; 31 | } 32 | 33 | message BlockParams{ 34 | int32 page_number = 1; 35 | int32 result_per_page = 2; 36 | } 37 | 38 | message BlockList { 39 | repeated Block blocks = 1; 40 | } 41 | 42 | message Block { 43 | int32 version = 1; 44 | int64 height = 2; 45 | int64 time_stamp = 3; 46 | string prev_hash = 4; 47 | string hash = 5; 48 | string transactions = 6; 49 | string validator = 7; 50 | double validator_balance = 8; 51 | string merkle_root = 9; 52 | int32 num_of_tx = 10; 53 | double total_amount = 11; 54 | double total_reward = 12; 55 | int32 difficulty = 13; 56 | int32 nonce = 14; 57 | int32 size = 15; 58 | int32 build_time = 16; 59 | string signature = 17; 60 | } 61 | -------------------------------------------------------------------------------- /UbudKusCoin/Protos/transaction.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service TransactionService { 12 | rpc Receive(TransactionPost) returns (TransactionStatus); 13 | rpc Transfer(TransactionPost) returns (TransactionStatus); 14 | rpc GetByHash(Transaction) returns (Transaction); 15 | rpc GetRangeByAddress(TransactionPaging) returns (TransactionList); 16 | rpc GetRange(TransactionPaging) returns (TransactionList); 17 | rpc GetPoolRange(TransactionPaging) returns (TransactionList); 18 | rpc GetPendingTxns(TransactionPaging) returns (TransactionList); 19 | } 20 | 21 | message TransactionPaging{ 22 | string address = 1; 23 | int64 height = 2; 24 | int32 page_number = 3; 25 | int32 result_per_page = 4; 26 | } 27 | 28 | message TransactionGet{ 29 | string address = 1; 30 | string hash = 2; 31 | } 32 | 33 | message TransactionPost{ 34 | Transaction Transaction = 1; 35 | string sending_from = 2; 36 | } 37 | 38 | message TransactionStatus{ 39 | string status = 1; 40 | string message = 2; 41 | } 42 | 43 | message TransactionList { 44 | repeated Transaction transactions = 1; 45 | } 46 | 47 | message Transaction{ 48 | string hash = 1; 49 | int64 time_stamp = 2; 50 | string sender = 3; 51 | string recipient = 4; 52 | double amount = 5; 53 | double fee = 6; 54 | int64 height = 7; 55 | string signature = 8; 56 | string pub_key = 9; 57 | string tx_type = 10; 58 | } -------------------------------------------------------------------------------- /ConsoleWallet/Protos/transaction.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service TransactionService { 12 | rpc Receive(TransactionPost) returns (TransactionStatus); 13 | rpc Transfer(TransactionPost) returns (TransactionStatus); 14 | rpc GetByHash(Transaction) returns (Transaction); 15 | rpc GetRangeByAddress(TransactionPaging) returns (TransactionList); 16 | rpc GetRange(TransactionPaging) returns (TransactionList); 17 | rpc GetPoolRange(TransactionPaging) returns (TransactionList); 18 | rpc GetPendingTxns(TransactionPaging) returns (TransactionList); 19 | } 20 | 21 | message TransactionPaging{ 22 | string address = 1; 23 | int64 height = 2; 24 | int32 page_number = 3; 25 | int32 result_per_page = 4; 26 | } 27 | 28 | message TransactionGet{ 29 | string address = 1; 30 | string hash = 2; 31 | } 32 | 33 | message TransactionPost{ 34 | Transaction Transaction = 1; 35 | string sending_from = 2; 36 | } 37 | 38 | message TransactionStatus{ 39 | string status = 1; 40 | string message = 2; 41 | } 42 | 43 | message TransactionList { 44 | repeated Transaction transactions = 1; 45 | } 46 | 47 | message Transaction{ 48 | string hash = 1; 49 | int64 time_stamp = 2; 50 | string sender = 3; 51 | string recipient = 4; 52 | double amount = 5; 53 | double fee = 6; 54 | int64 height = 7; 55 | string signature = 8; 56 | string pub_key = 9; 57 | string tx_type = 10; 58 | } -------------------------------------------------------------------------------- /UbudKusCoin/Services/ServicePool.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using UbudKusCoin.P2P; 9 | 10 | namespace UbudKusCoin.Services 11 | { 12 | public static class ServicePool 13 | { 14 | public static MintingService MintingService { set; get; } 15 | public static DbService DbService { set; get; } 16 | public static FacadeService FacadeService { set; get; } 17 | public static WalletService WalletService { set; get; } 18 | public static P2PService P2PService { set; get; } 19 | 20 | public static void Add( 21 | WalletService wallet, 22 | DbService db, 23 | FacadeService facade, 24 | MintingService minter, 25 | P2PService p2p) 26 | { 27 | WalletService = wallet; 28 | DbService = db; 29 | FacadeService = facade; 30 | MintingService = minter; 31 | P2PService = p2p; 32 | } 33 | 34 | public static void Start() 35 | { 36 | WalletService.Start(); 37 | DbService.Start(); 38 | FacadeService.start(); 39 | P2PService.Start(); 40 | MintingService.Start(); 41 | } 42 | 43 | public static void Stop() 44 | { 45 | //stop when application exit 46 | //WalletService.Stop(); 47 | DbService.Stop(); 48 | //FacadeService.Stop(); 49 | //P2PService.Stop(); 50 | MintingService.Stop(); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /BlockExplorer/Protos/transaction.proto: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara. markbrain2013[at]gmail.com 2 | // 3 | // Ubudkuscoin is free software distributed under the MIT software license, 4 | // Redistribution and use in source and binary forms with or without 5 | // modifications are permitted. 6 | 7 | syntax = "proto3"; 8 | 9 | option csharp_namespace = "UbudKusCoin.Grpc"; 10 | 11 | service TransactionService { 12 | rpc Receive(TransactionPost) returns (TransactionStatus); 13 | rpc Transfer(TransactionPost) returns (TransactionStatus); 14 | rpc GetByHash(Transaction) returns (Transaction); 15 | rpc GetRangeByAddress(TransactionPaging) returns (TransactionList); 16 | rpc GetRangeByHeight(TransactionPaging) returns (TransactionList); 17 | rpc GetRange(TransactionPaging) returns (TransactionList); 18 | rpc GetPoolRange(TransactionPaging) returns (TransactionList); 19 | rpc GetPendingTxns(TransactionPaging) returns (TransactionList); 20 | } 21 | 22 | message TransactionPaging{ 23 | string address = 1; 24 | int64 height = 2; 25 | int32 page_number = 3; 26 | int32 result_per_page = 4; 27 | } 28 | 29 | message TransactionGet{ 30 | string address = 1; 31 | string hash = 2; 32 | } 33 | 34 | message TransactionPost{ 35 | Transaction Transaction = 1; 36 | string sending_from = 2; 37 | } 38 | 39 | message TransactionStatus{ 40 | string status = 1; 41 | string message = 2; 42 | } 43 | 44 | message TransactionList { 45 | repeated Transaction transactions = 1; 46 | } 47 | 48 | message Transaction{ 49 | string hash = 1; 50 | int64 time_stamp = 2; 51 | string sender = 3; 52 | string recipient = 4; 53 | double amount = 5; 54 | double fee = 6; 55 | int64 height = 7; 56 | string signature = 8; 57 | string pub_key = 9; 58 | string tx_type = 10; 59 | } -------------------------------------------------------------------------------- /UbudKusCoin/Others/Constants.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | namespace UbudKusCoin.Others 9 | { 10 | public class Constants 11 | { 12 | public const int VERSION = 0; 13 | public const double DEFAULT_TRANSACTION_FEE = 0.001; 14 | public const double COINT_REWARD = 0.001f; 15 | public const string TBL_BLOCKS = "tbl_blocks"; 16 | public const string TBL_TRANSACTIONS = "tbl_txns"; 17 | public const string TBL_TRANSACTIONS_POOL = "tbl_txns_pool"; 18 | public const string TBL_STAKES = "tbl_stakes"; 19 | public const string TBL_PEERS = "tbl_peers"; 20 | public const string TBL_ACCOUNTS = "tbl_accounts"; 21 | public const string TXN_TYPE_STAKE = "Staking"; 22 | public const string TXN_TYPE_TRANSFER = "Transfer"; 23 | public const string TXN_TYPE_VALIDATOR_FEE = "Validation_Fee"; 24 | public const string TXN_STATUS_SUCCESS = "Success"; 25 | public const string TXN_STATUS_FAIL = "Fail"; 26 | public const string MESSAGE_TYPE_INV = "INVENTORY"; 27 | public const string MESSAGE_TYPE_GET_BLOCKS = "GET_BLOCKS"; 28 | public const string MESSAGE_TYPE_GET_DATA = "GET_DATA"; 29 | public const string MESSAGE_TYPE_STATE = "NODE_SATE"; 30 | public const string MESSAGE_SEPARATOR = "||"; 31 | public const string MESSAGE_TYPE_BLOCK = "BLOCK"; 32 | public const string MESSAGE_TYPE_TRANSACTION = "TRANSACTION"; 33 | public const int TXN_THRESHOLD = 5; 34 | public const int BLOCK_GENERATION_INTERVAL = 30; 35 | public const int DIFFICULTY_ADJUSTMENT_INTERVAL = 10; 36 | public const string MESSAGE_TYPE_CLEAR_TRANSACTIONS = "CLEAR_TRANSACTIONS"; 37 | } 38 | } -------------------------------------------------------------------------------- /UbudKusCoin/UbudKusCoin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net5.0 5 | true 6 | 30e6811d-fd4d-4923-9f26-64173fb52774 7 | 8 | 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ConsoleWallet/Others/Utils.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using System.Security.Cryptography; 10 | using System.Text; 11 | using UbudKusCoin.Grpc; 12 | 13 | namespace UbudKusCoin.ConsoleWallet.Others 14 | { 15 | public static class Utils 16 | { 17 | public static string GenHash(string data) 18 | { 19 | byte[] bytes = Encoding.UTF8.GetBytes(data); 20 | byte[] hash = SHA256.Create().ComputeHash(bytes); 21 | return Convert.ToHexString(hash).ToLower(); 22 | } 23 | 24 | public static DateTime ToDateTime(long unixTime) 25 | { 26 | DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 27 | return dtDateTime.AddSeconds(unixTime).ToLocalTime(); 28 | } 29 | 30 | public static long GetTime() 31 | { 32 | long epochTicks = new DateTime(1970, 1, 1).Ticks; 33 | long nowTicks = DateTime.UtcNow.Ticks; 34 | return (nowTicks - epochTicks) / TimeSpan.TicksPerSecond; 35 | } 36 | 37 | public static string StringToHex(string data) 38 | { 39 | byte[] bytes = Encoding.UTF8.GetBytes(data); 40 | return BytesToHex(bytes); 41 | } 42 | 43 | public static string BytesToHex(byte[] bytes) 44 | { 45 | return Convert.ToHexString(bytes).ToLower(); 46 | } 47 | 48 | public static byte[] HexToBytes(string hex) 49 | { 50 | int NumberChars = hex.Length; 51 | byte[] bytes = new byte[NumberChars / 2]; 52 | for (int i = 0; i < NumberChars; i += 2) 53 | { 54 | bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); 55 | } 56 | 57 | return bytes; 58 | } 59 | 60 | public static string GetTransactionHash(Transaction txn) 61 | { 62 | return GenHash(GenHash($"{txn.TimeStamp}{txn.Sender}{txn.Amount}{txn.Fee}{txn.Recipient}")); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /UbudKusCoin/DB/PoolTransactionsDb.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Collections.Generic; 9 | using LiteDB; 10 | using UbudKusCoin.Grpc; 11 | using UbudKusCoin.Others; 12 | 13 | namespace UbudKusCoin.DB 14 | { 15 | public class PoolTransactionsDb 16 | { 17 | private readonly LiteDatabase _db; 18 | 19 | public PoolTransactionsDb(LiteDatabase db) 20 | { 21 | _db = db; 22 | } 23 | 24 | public void Add(Transaction transaction) 25 | { 26 | var transactions = GetAll(); 27 | transactions.Insert(transaction); 28 | } 29 | 30 | public Transaction GetByHash(string hash) 31 | { 32 | var transactions = GetAll(); 33 | if (transactions is null || transactions.Count() < 1) 34 | { 35 | return null; 36 | } 37 | 38 | transactions.EnsureIndex(x => x.Hash); 39 | 40 | return transactions.FindOne(x => x.Hash == hash); 41 | } 42 | 43 | public IEnumerable GetRange(int pageNumber, int resultPerPage) 44 | { 45 | var transactions = GetAll(); 46 | if (transactions is null || transactions.Count() < 1) 47 | { 48 | return null; 49 | } 50 | 51 | transactions.EnsureIndex(x => x.TimeStamp); 52 | 53 | var query = transactions.Query() 54 | .OrderByDescending(x => x.TimeStamp) 55 | .Offset((pageNumber - 1) * resultPerPage) 56 | .Limit(resultPerPage).ToList(); 57 | 58 | return query; 59 | } 60 | 61 | 62 | public void DeleteAll() 63 | { 64 | var transactions = GetAll(); 65 | if (transactions is null || transactions.Count() < 1) 66 | { 67 | return; 68 | } 69 | 70 | transactions.DeleteAll(); 71 | } 72 | 73 | public ILiteCollection GetAll() 74 | { 75 | return _db.GetCollection(Constants.TBL_TRANSACTIONS_POOL); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /UbudKusCoin/DB/PeerDb.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Collections.Generic; 9 | using LiteDB; 10 | using UbudKusCoin.Grpc; 11 | using UbudKusCoin.Others; 12 | 13 | namespace UbudKusCoin.DB 14 | { 15 | /// 16 | /// Peer database, for add, update list of peers 17 | /// 18 | public class PeerDb 19 | { 20 | private readonly LiteDatabase _db; 21 | 22 | public PeerDb(LiteDatabase db) 23 | { 24 | _db = db; 25 | } 26 | 27 | /// 28 | /// Add a peer 29 | /// 30 | public void Add(Peer peer) 31 | { 32 | var existingPeer = GetByAddress(peer.Address); 33 | if (existingPeer is null) 34 | { 35 | GetAll().Insert(peer); 36 | } 37 | } 38 | 39 | /// 40 | /// Get list of peer, page number and number of row per page 41 | /// 42 | public List GetRange(int pageNumber, int resultPerPage) 43 | { 44 | var peers = GetAll(); 45 | 46 | peers.EnsureIndex(x => x.LastReach); 47 | 48 | var query = peers.Query() 49 | .OrderByDescending(x => x.LastReach) 50 | .Offset((pageNumber - 1) * resultPerPage) 51 | .Limit(resultPerPage).ToList(); 52 | 53 | return query; 54 | } 55 | 56 | 57 | /// 58 | /// Get all peer 59 | /// 60 | public ILiteCollection GetAll() 61 | { 62 | var peers = _db.GetCollection(Constants.TBL_PEERS); 63 | 64 | peers.EnsureIndex(x => x.LastReach); 65 | 66 | return peers; 67 | } 68 | 69 | /// 70 | /// Get peer by network address/IP 71 | /// 72 | public Peer GetByAddress(string address) 73 | { 74 | var peers = GetAll(); 75 | if (peers is null) 76 | { 77 | return null; 78 | } 79 | 80 | peers.EnsureIndex(x => x.Address); 81 | 82 | return peers.FindOne(x => x.Address == address); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /UbudKusCoin/Startup.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using Microsoft.AspNetCore.Builder; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.AspNetCore.Http; 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Hosting; 13 | using UbudKusCoin.Grpc; 14 | 15 | namespace UbudKusCoin 16 | { 17 | public class Startup 18 | { 19 | public static void ConfigureServices(IServiceCollection services) 20 | { 21 | services.AddGrpc(); 22 | services.AddCors(o => o.AddPolicy("AllowAll", builder => 23 | { 24 | builder.AllowAnyOrigin() 25 | .AllowAnyMethod() 26 | .AllowAnyHeader() 27 | .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding"); 28 | })); 29 | } 30 | 31 | public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) 32 | { 33 | if (env.IsDevelopment()) 34 | { 35 | app.UseDeveloperExceptionPage(); 36 | } 37 | else 38 | { 39 | app.UseExceptionHandler("/Error"); 40 | } 41 | 42 | app.UseRouting(); 43 | // add support grpc call from web app, Must be added between UseRouting and UseEndpoints 44 | app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true }); 45 | app.UseCors(); 46 | app.UseEndpoints(endpoints => 47 | { 48 | endpoints.MapGrpcService().RequireCors("AllowAll"); 49 | endpoints.MapGrpcService().RequireCors("AllowAll"); 50 | endpoints.MapGrpcService().RequireCors("AllowAll"); 51 | endpoints.MapGrpcService().RequireCors("AllowAll"); 52 | endpoints.MapGrpcService().RequireCors("AllowAll"); 53 | endpoints.MapGet("/", async context => 54 | { 55 | await context.Response.WriteAsync( 56 | "Communication with gRPC endpoints" + 57 | " must be made through a gRPC client."); 58 | }); 59 | }); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /UbudKusCoin/Program.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.AspNetCore.Server.Kestrel.Core; 11 | using Microsoft.Extensions.Hosting; 12 | using UbudKusCoin.Services; 13 | using UbudKusCoin.P2P; 14 | using Microsoft.Extensions.Logging; 15 | 16 | namespace UbudKusCoin 17 | { 18 | public class Program 19 | { 20 | public static void Main(string[] args) 21 | { 22 | DotNetEnv.Env.Load(); 23 | DotNetEnv.Env.TraversePath().Load(); 24 | 25 | ServicePool.Add( 26 | new WalletService(), 27 | new DbService(), 28 | new FacadeService(), 29 | new MintingService(), 30 | new P2PService() 31 | ); 32 | ServicePool.Start(); 33 | 34 | // grpc 35 | IHost host = CreateHostBuilder(args).Build(); 36 | host.Run(); 37 | } 38 | 39 | public static IHostBuilder CreateHostBuilder(string[] args) => 40 | Host.CreateDefaultBuilder(args) 41 | .UseSystemd() 42 | .ConfigureWebHostDefaults(webBuilder => 43 | { 44 | webBuilder.ConfigureKestrel(options => 45 | { 46 | var GRPC_WEB_PORT = DotNetEnv.Env.GetInt("GRPC_WEB_PORT"); 47 | var GRPC_PORT = DotNetEnv.Env.GetInt("GRPC_PORT"); 48 | 49 | options.ListenAnyIP(GRPC_WEB_PORT, listenOptions => listenOptions.Protocols = HttpProtocols.Http1AndHttp2); //webapi 50 | options.ListenAnyIP(GRPC_PORT, listenOptions => listenOptions.Protocols = HttpProtocols.Http2); //grpc 51 | }); 52 | 53 | // start 54 | webBuilder.UseStartup() 55 | // .ConfigureLogging(loggingBuilder => loggingBuilder.ClearProviders()); 56 | .ConfigureLogging((Action)((hostingContext, logging) => 57 | { 58 | // logging.AddConfiguration((IConfiguration)hostingContext.Configuration.GetSection("Logging")); 59 | // logging.AddConsole(); 60 | // logging.AddDebug(); 61 | // logging.AddEventSourceLogger(); 62 | logging.ClearProviders(); 63 | })); 64 | //=== 65 | }); 66 | } 67 | } -------------------------------------------------------------------------------- /UbudKusCoin/Facade/PeerFacade.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Linq; 9 | using System; 10 | using System.Collections.Generic; 11 | using UbudKusCoin.Others; 12 | using UbudKusCoin.Services; 13 | using UbudKusCoin.Grpc; 14 | 15 | namespace UbudKusCoin.Facade 16 | { 17 | public class Inventory 18 | { 19 | public string Type { set; get; } 20 | public IList Items { set; get; } 21 | } 22 | 23 | public class PeerFacade 24 | { 25 | public string NodeAddress { get; set; } 26 | public List InitialPeers { get; set; } 27 | 28 | public PeerFacade() 29 | { 30 | Initialize(); 31 | Console.WriteLine("...... Peer innitialized."); 32 | } 33 | 34 | internal void Initialize() 35 | { 36 | NodeAddress = DotNetEnv.Env.GetString("NODE_ADDRESS"); 37 | var KnowPeers = ServicePool.DbService.PeerDb.GetAll(); 38 | if (KnowPeers.Count() < 1) 39 | { 40 | InitialPeers = new List(); 41 | var bootstrapPeers = DotNetEnv.Env.GetString("BOOTSRTAP_PEERS").Replace(" ", ""); 42 | var tempPeers = bootstrapPeers.Split(","); 43 | 44 | for (int i = 0; i < tempPeers.Length; i++) 45 | { 46 | var newPeer = new Peer 47 | { 48 | Address = tempPeers[i], 49 | IsBootstrap = true, 50 | IsCanreach = false, 51 | LastReach = UkcUtils.GetTime() 52 | }; 53 | 54 | ServicePool.DbService.PeerDb.Add(newPeer); 55 | InitialPeers.Add(newPeer); 56 | } 57 | } 58 | } 59 | 60 | public List GetKnownPeers() 61 | { 62 | return ServicePool.DbService.PeerDb.GetAll().FindAll().ToList(); 63 | } 64 | 65 | public NodeState GetNodeState() 66 | { 67 | var lastBlock = ServicePool.DbService.BlockDb.GetLast(); 68 | var nodeState = new NodeState 69 | { 70 | Version = Constants.VERSION, 71 | Height = lastBlock.Height, 72 | Address = NodeAddress, 73 | Hash = lastBlock.Hash 74 | }; 75 | 76 | nodeState.KnownPeers.AddRange(GetKnownPeers()); 77 | return nodeState; 78 | } 79 | 80 | public void Add(Peer peer) 81 | { 82 | ServicePool.DbService.PeerDb.Add(peer); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /ConsoleWallet/Wallet.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Security.Cryptography; 9 | using NBitcoin.DataEncoders; 10 | using NBitcoin; 11 | 12 | namespace UbudKusCoin.ConsoleWallet 13 | { 14 | public class KeyPair 15 | { 16 | public ExtKey PrivateKey { set; get; } 17 | public ExtPubKey PublicKey { set; get; } 18 | public string PublicKeyHex { set; get; } 19 | } 20 | 21 | public class Wallet 22 | { 23 | public KeyPair KeyPair { get; set; } 24 | public Mnemonic Mnemonic { set; get; } 25 | public string Passphrase { set; get; } 26 | 27 | public Wallet() 28 | { 29 | Mnemonic = new Mnemonic(Wordlist.English, WordCount.Twelve); 30 | Passphrase = Mnemonic.ToString(); 31 | KeyPair = GenerateKeyPair(Mnemonic, 0); 32 | } 33 | 34 | public Wallet(string passphrase) 35 | { 36 | Mnemonic = new Mnemonic(passphrase); 37 | Passphrase = Mnemonic.ToString(); 38 | KeyPair = GenerateKeyPair(Mnemonic, 0); 39 | } 40 | 41 | public ExtPubKey GetPublicKey() 42 | { 43 | return KeyPair.PublicKey; 44 | } 45 | 46 | public KeyPair GetKeyPair() 47 | { 48 | return KeyPair; 49 | } 50 | 51 | public string GetAddress() 52 | { 53 | byte[] bytes = SHA256.Create().ComputeHash(KeyPair.PublicKey.ToBytes()); 54 | return Encoders.Base58.EncodeData(bytes); 55 | } 56 | 57 | public string Sign(string dataHash) 58 | { 59 | return KeyPair.PrivateKey.PrivateKey.SignMessage(dataHash); 60 | } 61 | 62 | public static bool verifySignature(string publicKeyHex, string signature, string dataHash) 63 | { 64 | var pubKey = new PubKey(publicKeyHex); 65 | return pubKey.VerifyMessage(dataHash, signature); 66 | } 67 | 68 | public static KeyPair GenerateKeyPair(Mnemonic mnemonic, int path) 69 | { 70 | var masterKey = mnemonic.DeriveExtKey(); 71 | ExtPubKey masterPubKey = masterKey.Neuter(); 72 | ExtKey privateKeyDer = masterKey.Derive((uint)path); 73 | ExtPubKey publicKeyDer = masterPubKey.Derive((uint)path); 74 | 75 | var publicKeyHex = publicKeyDer.PubKey.ToHex(); 76 | var keyPair = new KeyPair() 77 | { 78 | PrivateKey = privateKeyDer, 79 | PublicKeyHex = publicKeyHex, 80 | PublicKey = publicKeyDer, 81 | }; 82 | 83 | return keyPair; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /UbudKusCoin/Services/WalletService.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using System.Security.Cryptography; 10 | using NBitcoin; 11 | using NBitcoin.DataEncoders; 12 | 13 | namespace UbudKusCoin.Services 14 | { 15 | public class KeyPair 16 | { 17 | public ExtKey PrivateKey { set; get; } 18 | public ExtPubKey PublicKey { set; get; } 19 | public string PublicKeyHex { set; get; } 20 | } 21 | 22 | public class WalletService 23 | { 24 | public KeyPair KeyPair { get; set; } 25 | public Mnemonic Mnemonic { set; get; } 26 | public string Passphrase { set; get; } 27 | 28 | public WalletService() 29 | { 30 | Passphrase = DotNetEnv.Env.GetString("NODE_PASSPHRASE"); 31 | } 32 | 33 | public void Start() 34 | { 35 | Console.WriteLine("... Wallet service is starting"); 36 | Mnemonic = new Mnemonic(Passphrase); 37 | KeyPair = GenerateKeyPair(Mnemonic, 0); 38 | Console.WriteLine("...... Wallet service is ready"); 39 | } 40 | 41 | public static KeyPair GenerateKeyPair(Mnemonic mnemonic, int path) 42 | { 43 | var masterKey = mnemonic.DeriveExtKey(); 44 | ExtPubKey masterPubKey = masterKey.Neuter(); 45 | ExtKey privateKeyDer = masterKey.Derive((uint)path); 46 | ExtPubKey publicKeyDer = masterPubKey.Derive((uint)path); 47 | 48 | var publicKeyHex = publicKeyDer.PubKey.ToHex(); 49 | var keyPair = new KeyPair() 50 | { 51 | PrivateKey = privateKeyDer, 52 | PublicKeyHex = publicKeyHex, 53 | PublicKey = publicKeyDer, 54 | }; 55 | 56 | return keyPair; 57 | } 58 | 59 | public ExtPubKey GetPublicKey() 60 | { 61 | return KeyPair.PublicKey; 62 | } 63 | 64 | public KeyPair GetKeyPair() 65 | { 66 | return KeyPair; 67 | } 68 | 69 | public string GetAddress() 70 | { 71 | byte[] hash = SHA256.Create().ComputeHash(KeyPair.PublicKey.ToBytes()); 72 | return Encoders.Base58.EncodeData(hash); 73 | } 74 | 75 | public string Sign(string dataHash) 76 | { 77 | return KeyPair.PrivateKey.PrivateKey.SignMessage(dataHash); 78 | } 79 | 80 | public static bool CheckSignature(string publicKeyHex, string signature, string dataHash) 81 | { 82 | var pubKey = new PubKey(publicKeyHex); 83 | return pubKey.VerifyMessage(dataHash, signature); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /UbudKusCoin/DB/AccountDb.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Collections.Generic; 9 | using LiteDB; 10 | using UbudKusCoin.Grpc; 11 | using UbudKusCoin.Others; 12 | 13 | namespace UbudKusCoin.DB 14 | { 15 | /// 16 | /// Account Database, for Add. Update and retrieve account 17 | /// 18 | public class AccountDb 19 | { 20 | private readonly LiteDatabase _db; 21 | 22 | public AccountDb(LiteDatabase db) 23 | { 24 | _db = db; 25 | } 26 | 27 | /// 28 | /// Add new Account 29 | /// 30 | public void Add(Account acc) 31 | { 32 | var accounts = GetAll(); 33 | accounts.Insert(acc); 34 | } 35 | 36 | /// 37 | /// update an Account 38 | /// 39 | public void Update(Account acc) 40 | { 41 | var accounts = GetAll(); 42 | accounts.Update(acc); 43 | } 44 | 45 | /// 46 | /// Get accounts with paging, page number and result per page 47 | /// 48 | public IEnumerable GetRange(int pageNumber, int resultPerPage) 49 | { 50 | var accounts = GetAll(); 51 | 52 | accounts.EnsureIndex(x => x.Balance); 53 | 54 | var query = accounts.Query() 55 | .OrderByDescending(x => x.Balance) 56 | .Offset((pageNumber - 1) * resultPerPage) 57 | .Limit(resultPerPage).ToList(); 58 | 59 | return query; 60 | } 61 | 62 | /// 63 | /// Get Account by it's Address 64 | /// 65 | public Account GetByAddress(string address) 66 | { 67 | var accounts = GetAll(); 68 | if (accounts is null) 69 | { 70 | return null; 71 | } 72 | 73 | accounts.EnsureIndex(x => x.Address); 74 | 75 | return accounts.FindOne(x => x.Address == address); 76 | } 77 | 78 | /// 79 | /// Get an Account by its Public Key 80 | /// 81 | public Account GetByPubKey(string pubkey) 82 | { 83 | var accounts = GetAll(); 84 | 85 | accounts.EnsureIndex(x => x.PubKey); 86 | 87 | return accounts.FindOne(x => x.PubKey == pubkey); 88 | } 89 | 90 | private ILiteCollection GetAll() 91 | { 92 | return _db.GetCollection(Constants.TBL_ACCOUNTS); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /UbudKusCoin/DB/StakeDb.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using LiteDB; 9 | using UbudKusCoin.Grpc; 10 | using UbudKusCoin.Others; 11 | 12 | namespace UbudKusCoin.DB 13 | { 14 | /// 15 | /// Stake database 16 | /// 17 | public class StakeDb 18 | { 19 | private readonly LiteDatabase _db; 20 | 21 | public StakeDb(LiteDatabase db) 22 | { 23 | _db = db; 24 | } 25 | 26 | /// 27 | /// add or update stake 28 | /// 29 | public void AddOrUpdate(Stake stake) 30 | { 31 | var locStake = GetByAddress(stake.Address); 32 | if (locStake is null) 33 | { 34 | GetAll().Insert(stake); 35 | } 36 | 37 | GetAll().Update(stake); 38 | } 39 | 40 | /// 41 | /// Delete all stake 42 | /// 43 | public void DeleteAll() 44 | { 45 | var stakers = GetAll(); 46 | if (stakers is null || stakers.Count() < 1) 47 | { 48 | return; 49 | } 50 | 51 | stakers.DeleteAll(); 52 | } 53 | 54 | /// 55 | /// Get maximum stake, base on amount 56 | /// 57 | public Stake GetMax() 58 | { 59 | var stakes = GetAll(); 60 | if (stakes is null || stakes.Count() < 1) 61 | { 62 | return null; 63 | } 64 | 65 | stakes.EnsureIndex(x => x.Amount); 66 | 67 | var query = stakes.Query() 68 | .OrderByDescending(x => x.Amount); 69 | 70 | return query.FirstOrDefault(); 71 | } 72 | 73 | /// 74 | /// Get stake by address 75 | /// 76 | public Stake GetByAddress(string address) 77 | { 78 | var stakes = GetAll(); 79 | if (stakes is null) 80 | { 81 | return null; 82 | } 83 | 84 | stakes.EnsureIndex(x => x.Address); 85 | 86 | var stake = stakes.FindOne(x => x.Address == address); 87 | 88 | return stake; 89 | } 90 | 91 | /// 92 | /// Get all stake 93 | /// 94 | public ILiteCollection GetAll() 95 | { 96 | var stakes = _db.GetCollection(Constants.TBL_STAKES); 97 | 98 | stakes.EnsureIndex(x => x.Amount); 99 | 100 | return stakes; 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /UbudKusCoin/Services/DBService.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using LiteDB; 10 | using UbudKusCoin.DB; 11 | 12 | namespace UbudKusCoin.Services 13 | { 14 | public class DbService 15 | { 16 | private readonly LiteDatabase DB_BLOCK; 17 | private readonly LiteDatabase DB_ACCOUNT; 18 | private readonly LiteDatabase DB_TRANSACTION; 19 | private readonly LiteDatabase DB_TRANSACTION_POOL; 20 | private readonly LiteDatabase DB_PEER; 21 | private readonly LiteDatabase DB_STAKE; 22 | 23 | public BlockDb BlockDb { get; set; } 24 | public TransactionDb TransactionDb { get; set; } 25 | public PeerDb PeerDb { get; set; } 26 | 27 | public AccountDb AccountDb { get; set; } 28 | public PoolTransactionsDb PoolTransactionsDb { get; set; } 29 | public StakeDb StakeDb { get; set; } 30 | 31 | // I use multiple database, to minimize database size for transaction, block 32 | // size will smaller for each database 33 | public DbService() 34 | { 35 | //create db folder 36 | if (!System.IO.Directory.Exists(@"DbFiles")) 37 | System.IO.Directory.CreateDirectory(@"DbFiles"); 38 | 39 | DB_BLOCK = InitializeDatabase(@"DbFiles//block.db"); 40 | DB_ACCOUNT = InitializeDatabase(@"DbFiles//account.db"); 41 | DB_TRANSACTION = InitializeDatabase(@"DbFiles//transaction.db"); 42 | DB_TRANSACTION_POOL = InitializeDatabase(@"DbFiles//transaction_pool.db"); 43 | DB_STAKE = InitializeDatabase(@"DbFiles//stake.db"); 44 | DB_PEER = InitializeDatabase(@"DbFiles//peer.db"); 45 | } 46 | 47 | private LiteDatabase InitializeDatabase(string path) 48 | { 49 | return new LiteDatabase(path); 50 | } 51 | 52 | public void Start() 53 | { 54 | Console.WriteLine("... DB Service is starting"); 55 | BlockDb = new BlockDb(DB_BLOCK); 56 | AccountDb = new AccountDb(DB_ACCOUNT); 57 | TransactionDb = new TransactionDb(DB_ACCOUNT); 58 | PoolTransactionsDb = new PoolTransactionsDb(DB_TRANSACTION_POOL); 59 | StakeDb = new StakeDb(DB_STAKE); 60 | PeerDb = new PeerDb(DB_PEER); 61 | Console.WriteLine("...... DB Service is ready"); 62 | } 63 | 64 | public void Stop() 65 | { 66 | Console.WriteLine("... DB Service is stopping..."); 67 | DB_BLOCK.Dispose(); 68 | DB_STAKE.Dispose(); 69 | DB_TRANSACTION.Dispose(); 70 | DB_TRANSACTION_POOL.Dispose(); 71 | DB_PEER.Dispose(); 72 | DB_ACCOUNT.Dispose(); 73 | Console.WriteLine("... DB Service has been disposed"); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /UbudKusCoin/Grpc/BlockServiceImpl.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Threading.Tasks; 9 | using Grpc.Core; 10 | using UbudKusCoin.Services; 11 | using Newtonsoft.Json; 12 | using System.Collections.Generic; 13 | 14 | namespace UbudKusCoin.Grpc 15 | { 16 | public class BlockServiceImpl : BlockService.BlockServiceBase 17 | { 18 | public override Task Add(Block block, ServerCallContext context) 19 | { 20 | var lastBlock = ServicePool.DbService.BlockDb.GetLast(); 21 | 22 | // validate block hash 23 | if (block.PrevHash != lastBlock.Hash) 24 | { 25 | return Task.FromResult(new AddBlockStatus 26 | { 27 | Status = Others.Constants.TXN_STATUS_FAIL, 28 | Message = "hash not valid" 29 | }); 30 | } 31 | 32 | // validate block height 33 | if (block.Height != lastBlock.Height + 1) 34 | { 35 | return Task.FromResult(new AddBlockStatus 36 | { 37 | Status = Others.Constants.TXN_STATUS_FAIL, 38 | Message = "Invalid weight" 39 | }); 40 | } 41 | 42 | // Console.WriteLine("\n- - - - >> Receiving block , height: {0} \n- - - - >> from: {1}\n", block.Height, block.Validator); 43 | var addStatus = ServicePool.DbService.BlockDb.Add(block); 44 | //Console.WriteLine("- - - - >> Block added to db."); 45 | 46 | //extract transaction 47 | var transactions = JsonConvert.DeserializeObject>(block.Transactions); 48 | 49 | // update balances 50 | ServicePool.FacadeService.Account.UpdateBalance(transactions); 51 | 52 | // move pool to to transactions db 53 | ServicePool.FacadeService.Transaction.AddBulk(transactions); 54 | 55 | // clear mempool 56 | ServicePool.DbService.PoolTransactionsDb.DeleteAll(); 57 | 58 | return Task.FromResult(addStatus); 59 | } 60 | 61 | public override Task GetFirst(EmptyRequest request, ServerCallContext context) 62 | { 63 | var block = ServicePool.DbService.BlockDb.GetFirst(); 64 | return Task.FromResult(block); 65 | } 66 | 67 | public override Task GetLast(EmptyRequest request, ServerCallContext context) 68 | { 69 | var block = ServicePool.DbService.BlockDb.GetLast(); 70 | return Task.FromResult(block); 71 | } 72 | 73 | public override Task GetByHash(Block request, ServerCallContext context) 74 | { 75 | var block = ServicePool.DbService.BlockDb.GetByHash(request.Hash); 76 | return Task.FromResult(block); 77 | } 78 | 79 | public override Task GetByHeight(Block request, ServerCallContext context) 80 | { 81 | var block = ServicePool.DbService.BlockDb.GetByHeight(request.Height); 82 | return Task.FromResult(block); 83 | } 84 | 85 | public override Task GetRange(BlockParams request, ServerCallContext context) 86 | { 87 | var blocks = ServicePool.DbService.BlockDb.GetRange(request.PageNumber, request.ResultPerPage); 88 | var list = new BlockList(); 89 | list.Blocks.AddRange(blocks); 90 | return Task.FromResult(list); 91 | } 92 | 93 | public override Task GetRemains(StartingParam request, ServerCallContext context) 94 | { 95 | var blocks = ServicePool.DbService.BlockDb.GetRemaining(request.Height); 96 | var list = new BlockList(); 97 | list.Blocks.AddRange(blocks); 98 | return Task.FromResult(list); 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /UbudKusCoin.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UbudKusCoin", "UbudKusCoin\UbudKusCoin.csproj", "{BC93EA5B-096B-4AAE-8126-E9F15D2775EB}" 5 | EndProject 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{726E9E22-FEB4-48B3-81F5-943A4AE9723B}" 7 | ProjectSection(SolutionItems) = preProject 8 | .gitignore = .gitignore 9 | EndProjectSection 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleWallet", "ConsoleWallet\ConsoleWallet.csproj", "{BB617FED-A809-472E-8CEB-6AA91074214E}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlockExplorer", "BlockExplorer\BlockExplorer.csproj", "{E822DC99-5125-4477-8F20-230C283E344B}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | Debug|iPhoneSimulator = Debug|iPhoneSimulator 20 | Release|iPhoneSimulator = Release|iPhoneSimulator 21 | Debug|iPhone = Debug|iPhone 22 | Release|iPhone = Release|iPhone 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 30 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 31 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 32 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 33 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Debug|iPhone.ActiveCfg = Debug|Any CPU 34 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Debug|iPhone.Build.0 = Debug|Any CPU 35 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Release|iPhone.ActiveCfg = Release|Any CPU 36 | {BC93EA5B-096B-4AAE-8126-E9F15D2775EB}.Release|iPhone.Build.0 = Release|Any CPU 37 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 42 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 43 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 44 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 45 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Debug|iPhone.ActiveCfg = Debug|Any CPU 46 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Debug|iPhone.Build.0 = Debug|Any CPU 47 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Release|iPhone.ActiveCfg = Release|Any CPU 48 | {BB617FED-A809-472E-8CEB-6AA91074214E}.Release|iPhone.Build.0 = Release|Any CPU 49 | {E822DC99-5125-4477-8F20-230C283E344B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {E822DC99-5125-4477-8F20-230C283E344B}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {E822DC99-5125-4477-8F20-230C283E344B}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {E822DC99-5125-4477-8F20-230C283E344B}.Release|Any CPU.Build.0 = Release|Any CPU 53 | {E822DC99-5125-4477-8F20-230C283E344B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 54 | {E822DC99-5125-4477-8F20-230C283E344B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU 55 | {E822DC99-5125-4477-8F20-230C283E344B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 56 | {E822DC99-5125-4477-8F20-230C283E344B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU 57 | {E822DC99-5125-4477-8F20-230C283E344B}.Debug|iPhone.ActiveCfg = Debug|Any CPU 58 | {E822DC99-5125-4477-8F20-230C283E344B}.Debug|iPhone.Build.0 = Debug|Any CPU 59 | {E822DC99-5125-4477-8F20-230C283E344B}.Release|iPhone.ActiveCfg = Release|Any CPU 60 | {E822DC99-5125-4477-8F20-230C283E344B}.Release|iPhone.Build.0 = Release|Any CPU 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /UbudKusCoin/Facade/TransactionFacade.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using UbudKusCoin.Grpc; 12 | using UbudKusCoin.Others; 13 | using UbudKusCoin.Services; 14 | 15 | namespace UbudKusCoin.Facade 16 | { 17 | /// 18 | /// Transaction Facade 19 | /// 20 | public class TransactionFacade 21 | { 22 | public TransactionFacade() 23 | { 24 | Console.WriteLine("...... Transaction innitialized."); 25 | } 26 | 27 | /// 28 | /// Add some transactions in same times 29 | /// 30 | public bool AddBulk(List transactions) 31 | { 32 | return ServicePool.DbService.TransactionDb.AddBulk(transactions); 33 | } 34 | 35 | /// 36 | /// Create genesis transaction for each genesis account 37 | /// Sender and recipeint is same 38 | /// 39 | public List CreateGenesis() 40 | { 41 | var genesisTransactions = new List(); 42 | var timeStamp = UkcUtils.GetTime(); 43 | var accounts = ServicePool.FacadeService.Account.GetGenesis(); 44 | 45 | for (int i = 0; i < accounts.Count; i++) 46 | { 47 | var newTransaction = new Transaction() 48 | { 49 | TimeStamp = timeStamp, 50 | Sender = accounts[i].Address, 51 | Recipient = accounts[i].Address, 52 | Amount = accounts[i].Balance, 53 | Fee = 0.0f, 54 | Height = 1, 55 | PubKey = accounts[i].PubKey 56 | }; 57 | 58 | var transactionHash = GetHash(newTransaction); 59 | newTransaction.Hash = transactionHash; 60 | newTransaction.Signature = ServicePool.WalletService.Sign(transactionHash); 61 | 62 | genesisTransactions.Add(newTransaction); 63 | } 64 | 65 | return genesisTransactions; 66 | } 67 | 68 | /// 69 | /// Get transaction hash 70 | /// 71 | public string GetHash(Transaction txn) 72 | { 73 | var data = $"{txn.TimeStamp}{txn.Sender}{txn.Amount}{txn.Fee}{txn.Recipient}"; 74 | return UkcUtils.GenHash(UkcUtils.GenHash(data)); 75 | } 76 | 77 | public double GetBalance(string address) 78 | { 79 | var account = ServicePool.DbService.AccountDb.GetByAddress(address); 80 | if (account == null) 81 | { 82 | return 0; 83 | } 84 | 85 | return account.Balance; 86 | } 87 | 88 | public List GetForMinting(long weight) 89 | { 90 | // get transaction from pool 91 | var poolTransactions = ServicePool.DbService.PoolTransactionsDb.GetAll().FindAll().ToList(); 92 | var transactions = new List(); 93 | 94 | // validator will get coin reward from genesis account 95 | // to keep total coin in Blockchain not changed 96 | var conbaseTrx = new Transaction 97 | { 98 | TimeStamp = UkcUtils.GetTime(), 99 | Sender = "-", 100 | Signature = "-", 101 | PubKey = "-", 102 | Height = weight, 103 | Recipient = ServicePool.WalletService.GetAddress(), 104 | TxType = Constants.TXN_TYPE_VALIDATOR_FEE, 105 | Fee = 0, 106 | }; 107 | 108 | if (poolTransactions.Any()) 109 | { 110 | //sum all fees and give block creator as reward 111 | conbaseTrx.Amount = UkcUtils.GetTotalFees(poolTransactions); 112 | conbaseTrx.Hash = UkcUtils.GetTransactionHash(conbaseTrx); 113 | 114 | // add coinbase trx to list 115 | transactions.Add(conbaseTrx); 116 | transactions.AddRange(poolTransactions); 117 | } 118 | else 119 | { 120 | conbaseTrx.Hash = UkcUtils.GetTransactionHash(conbaseTrx); 121 | transactions.Add(conbaseTrx); 122 | } 123 | 124 | return transactions; 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /UbudKusCoin/DB/TransactionDb.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Collections.Generic; 9 | using LiteDB; 10 | using UbudKusCoin.Others; 11 | using UbudKusCoin.Grpc; 12 | 13 | namespace UbudKusCoin.DB 14 | { 15 | /// 16 | /// Transaction DB, for add, update transaction 17 | /// 18 | public class TransactionDb 19 | { 20 | private readonly LiteDatabase _db; 21 | 22 | public TransactionDb(LiteDatabase db) 23 | { 24 | _db = db; 25 | } 26 | 27 | /// 28 | /// Add some transaction in smae time 29 | /// 30 | public bool AddBulk(List transactions) 31 | { 32 | try 33 | { 34 | var collection = GetAll(); 35 | 36 | collection.InsertBulk(transactions); 37 | 38 | return true; 39 | } 40 | catch 41 | { 42 | return false; 43 | } 44 | } 45 | 46 | /// 47 | /// Add a transaction 48 | /// 49 | public bool Add(Transaction transaction) 50 | { 51 | try 52 | { 53 | var transactions = GetAll(); 54 | 55 | transactions.Insert(transaction); 56 | 57 | return true; 58 | } 59 | catch 60 | { 61 | return false; 62 | } 63 | } 64 | 65 | /// 66 | /// Get All Transactions by Address and with paging 67 | /// 68 | public IEnumerable GetRangeByAddress(string address, int pageNumber, int resultsPerPage) 69 | { 70 | var transactions = GetAll(); 71 | if (transactions is null || transactions.Count() < 1) 72 | { 73 | return null; 74 | } 75 | 76 | transactions.EnsureIndex(x => x.Sender); 77 | transactions.EnsureIndex(x => x.Recipient); 78 | 79 | var query = transactions.Query() 80 | .OrderByDescending(x => x.TimeStamp) 81 | .Where(x => x.Sender == address || x.Recipient == address) 82 | .Offset((pageNumber - 1) * resultsPerPage) 83 | .Limit(resultsPerPage).ToList(); 84 | 85 | return query; 86 | } 87 | 88 | /// 89 | /// Get Transaction by Hash 90 | /// 91 | public Transaction GetByHash(string hash) 92 | { 93 | var transactions = GetAll(); 94 | if (transactions is null || transactions.Count() < 1) 95 | { 96 | return null; 97 | } 98 | 99 | transactions.EnsureIndex(x => x.Hash); 100 | 101 | return transactions.FindOne(x => x.Hash == hash); 102 | } 103 | 104 | /// 105 | /// Get transactions 106 | /// 107 | public IEnumerable GetRange(int pageNumber, int resultPerPage) 108 | { 109 | var transactions = GetAll(); 110 | if (transactions is null || transactions.Count() < 1) 111 | { 112 | return null; 113 | } 114 | 115 | transactions.EnsureIndex(x => x.TimeStamp); 116 | 117 | var query = transactions.Query() 118 | .OrderByDescending(x => x.TimeStamp) 119 | .Offset((pageNumber - 1) * resultPerPage) 120 | .Limit(resultPerPage).ToList(); 121 | 122 | return query; 123 | } 124 | 125 | public IEnumerable GetLast(int num) 126 | { 127 | var transactions = GetAll(); 128 | if (transactions is null || transactions.Count() < 1) 129 | { 130 | return null; 131 | } 132 | 133 | transactions.EnsureIndex(x => x.TimeStamp); 134 | 135 | var query = transactions.Query() 136 | .OrderByDescending(x => x.TimeStamp) 137 | .Limit(num).ToList(); 138 | 139 | return query; 140 | } 141 | 142 | /// 143 | /// get one transaction by address 144 | /// 145 | public Transaction GetByAddress(string address) 146 | { 147 | var transactions = GetAll(); 148 | if (transactions is null || transactions.Count() < 1) 149 | { 150 | return null; 151 | } 152 | 153 | transactions.EnsureIndex(x => x.TimeStamp); 154 | var transaction = transactions.FindOne(x => x.Sender == address || x.Recipient == address); 155 | return transaction; 156 | } 157 | 158 | private ILiteCollection GetAll() 159 | { 160 | return _db.GetCollection(Constants.TBL_TRANSACTIONS); 161 | } 162 | } 163 | } -------------------------------------------------------------------------------- /UbudKusCoin/Facade/AccountFacade.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using UbudKusCoin.Grpc; 11 | using UbudKusCoin.Others; 12 | using UbudKusCoin.Services; 13 | 14 | namespace UbudKusCoin.Facade 15 | { 16 | public class AccountFacade 17 | { 18 | public AccountFacade() 19 | { 20 | Console.WriteLine("...... Account innitialized."); 21 | } 22 | 23 | public Account GetByAddress(string address) 24 | { 25 | return ServicePool.DbService.AccountDb.GetByAddress(address); 26 | } 27 | 28 | /// 29 | /// Genesis account have initial balance 30 | /// 31 | public List GetGenesis() 32 | { 33 | var timestamp = UkcUtils.GetTime(); 34 | var list = new List 35 | { 36 | new() 37 | { 38 | // live uniform pudding know thumb hand deposit critic relief asset demand barrel 39 | Address = "9SBqYME6T5trNHXqdsYPMPha4yWQbzxd4DPjJBR7KG9A", 40 | PubKey = "02c51f708f279643811af172b9f838aabb2cb4c90b683da9c5d4b81d70f00e9af2", 41 | Balance = 2000000000, 42 | TxnCount = 1, 43 | Created = timestamp, 44 | Updated = timestamp 45 | }, 46 | 47 | new() 48 | { 49 | // carbon snack lab junk moment shiver gas dry stem real scale cannon 50 | Address = "3pXA6G3o2bu3Mbp9k2NDfXGWPuhCMn4wvZeTAFCf4N5r", 51 | PubKey = "03155bbe7fa31d0ebfd779a50a02c1d9444bbf79deb90e1725216d5e8786c632f8", 52 | Balance = 3000000000, 53 | TxnCount = 2, 54 | Created = timestamp, 55 | Updated = timestamp 56 | }, 57 | }; 58 | 59 | return list; 60 | } 61 | 62 | /// 63 | /// Add amount to Balance 64 | /// 65 | public void AddToBalance(string to, double amount) 66 | { 67 | var acc = ServicePool.DbService.AccountDb.GetByAddress(to); 68 | if (acc is null) 69 | { 70 | acc = new Account 71 | { 72 | Address = to, 73 | Balance = amount, 74 | TxnCount = 1, 75 | Created = UkcUtils.GetTime(), 76 | Updated = UkcUtils.GetTime(), 77 | PubKey = "-" 78 | }; 79 | 80 | ServicePool.DbService.AccountDb.Add(acc); 81 | } 82 | else 83 | { 84 | acc.Balance += amount; 85 | acc.TxnCount += 1; 86 | acc.Updated = UkcUtils.GetTime(); 87 | ServicePool.DbService.AccountDb.Update(acc); 88 | } 89 | } 90 | 91 | /// 92 | /// Reduce amount from Balance 93 | /// 94 | public void ReduceFromBalance(string from, double amount, string publicKey) 95 | { 96 | var account = ServicePool.DbService.AccountDb.GetByAddress(from); 97 | if (account is null) 98 | { 99 | account = new Account 100 | { 101 | Address = from, 102 | Balance = -amount, 103 | TxnCount = 1, 104 | Created = UkcUtils.GetTime(), 105 | Updated = UkcUtils.GetTime(), 106 | PubKey = publicKey, 107 | }; 108 | 109 | ServicePool.DbService.AccountDb.Add(account); 110 | } 111 | else 112 | { 113 | account.Balance -= amount; 114 | account.TxnCount += 1; 115 | account.PubKey = publicKey; 116 | account.Updated = UkcUtils.GetTime(); 117 | 118 | ServicePool.DbService.AccountDb.Update(account); 119 | } 120 | } 121 | 122 | /// 123 | /// Update Balance 124 | /// 125 | public void UpdateBalance(List transactions) 126 | { 127 | foreach (var transaction in transactions) 128 | { 129 | ReduceFromBalance(transaction.Sender, transaction.Amount, transaction.PubKey); 130 | AddToBalance(transaction.Recipient, transaction.Amount); 131 | } 132 | } 133 | 134 | /// 135 | /// Update Genesis Account Balance 136 | /// 137 | public void UpdateBalanceGenesis(List transactions) 138 | { 139 | foreach (var transaction in transactions) 140 | { 141 | AddToBalance(transaction.Recipient, transaction.Amount); 142 | } 143 | } 144 | } 145 | } -------------------------------------------------------------------------------- /UbudKusCoin/Others/Utils.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Security.Cryptography; 12 | using System.Text; 13 | using UbudKusCoin.Grpc; 14 | 15 | namespace UbudKusCoin.Others 16 | { 17 | public static class UkcUtils 18 | { 19 | public static string GenHash(string data) 20 | { 21 | byte[] bytes = Encoding.UTF8.GetBytes(data); 22 | byte[] hash = SHA256.Create().ComputeHash(bytes); 23 | return BytesToHex(hash); 24 | } 25 | 26 | public static byte[] GenHashBytes(string data) 27 | { 28 | byte[] bytes = Encoding.UTF8.GetBytes(data); 29 | byte[] hash = SHA256.Create().ComputeHash(bytes); 30 | return hash; 31 | } 32 | 33 | public static string GenHashHex(string hex) 34 | { 35 | byte[] bytes = HexToBytes(hex); 36 | byte[] hash = SHA256.Create().ComputeHash(bytes); 37 | return BytesToHex(hash); 38 | } 39 | 40 | public static string BytesToHex(byte[] bytes) 41 | { 42 | return Convert.ToHexString(bytes).ToLower(); 43 | } 44 | 45 | public static byte[] HexToBytes(string hex) 46 | { 47 | return Enumerable.Range(0, hex.Length) 48 | .Where(x => x % 2 == 0) 49 | .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) 50 | .ToArray(); 51 | } 52 | 53 | public static DateTime ToDateTime(long unixTime) 54 | { 55 | DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 56 | dtDateTime = dtDateTime.AddSeconds(unixTime).ToLocalTime(); 57 | return dtDateTime; 58 | } 59 | 60 | public static long GetTime() 61 | { 62 | long epochTicks = new DateTime(1970, 1, 1).Ticks; 63 | long nowTicks = DateTime.UtcNow.Ticks; 64 | long tmStamp = ((nowTicks - epochTicks) / TimeSpan.TicksPerSecond); 65 | return tmStamp; 66 | } 67 | 68 | public static string CreateMerkleRoot(string[] txsHash) 69 | { 70 | while (true) 71 | { 72 | if (txsHash.Length == 0) 73 | { 74 | return string.Empty; 75 | } 76 | 77 | if (txsHash.Length == 1) 78 | { 79 | return txsHash[0]; 80 | } 81 | 82 | List newHashList = new List(); 83 | 84 | int len = (txsHash.Length % 2 != 0) ? txsHash.Length - 1 : txsHash.Length; 85 | 86 | for (int i = 0; i < len; i += 2) 87 | { 88 | newHashList.Add(DoubleHash(txsHash[i], txsHash[i + 1])); 89 | } 90 | 91 | if (len < txsHash.Length) 92 | { 93 | newHashList.Add(DoubleHash(txsHash[^1], txsHash[^1])); 94 | } 95 | 96 | txsHash = newHashList.ToArray(); 97 | } 98 | } 99 | 100 | static string DoubleHash(string leaf1, string leaf2) 101 | { 102 | byte[] leaf1Byte = HexToBytes(leaf1); 103 | byte[] leaf2Byte = HexToBytes(leaf2); 104 | 105 | var concatHash = leaf1Byte.Concat(leaf2Byte).ToArray(); 106 | SHA256 sha256 = SHA256.Create(); 107 | byte[] sendHash = sha256.ComputeHash(sha256.ComputeHash(concatHash)); 108 | 109 | return BytesToHex(sendHash).ToLower(); 110 | } 111 | 112 | public static double GetTotalFees(List txns) 113 | { 114 | return txns.AsEnumerable().Sum(x => x.Fee); 115 | } 116 | 117 | public static double GetTotalAmount(List txns) 118 | { 119 | return txns.AsEnumerable().Sum(x => x.Amount); 120 | } 121 | 122 | public static string GetTransactionHash(Transaction txn) 123 | { 124 | // Console.WriteLine(" get transaction hash {0}", txn); 125 | return GenHash(GenHash(txn.TimeStamp + txn.Sender + txn.Amount + txn.Fee + txn.Recipient)); 126 | // Console.WriteLine(" get transaction hash {0}", TxnId); 127 | } 128 | 129 | public static void PrintBlock(Block block) 130 | { 131 | Console.WriteLine("\n===========\nNew Block created"); 132 | Console.WriteLine(" = Height : {0}", block.Height); 133 | Console.WriteLine(" = Version : {0}", block.Version); 134 | Console.WriteLine(" = Prev Hash : {0}", block.PrevHash); 135 | Console.WriteLine(" = Hash : {0}", block.Hash); 136 | Console.WriteLine(" = Merkle Hash : {0}", block.MerkleRoot); 137 | Console.WriteLine(" = Timestamp : {0}", ToDateTime(block.TimeStamp)); 138 | Console.WriteLine(" = Difficulty : {0}", block.Difficulty); 139 | Console.WriteLine(" = Validator : {0}", block.Validator); 140 | Console.WriteLine(" = Nonce : {0}", block.Nonce); 141 | Console.WriteLine(" = Number Of Tx: {0}", block.NumOfTx); 142 | Console.WriteLine(" = Amout : {0}", block.TotalAmount); 143 | Console.WriteLine(" = Reward : {0}", block.TotalReward); 144 | Console.WriteLine(" = Size : {0}", block.Size); 145 | Console.WriteLine(" = Build Time : {0}", block.BuildTime); 146 | Console.WriteLine(" = Signature : {0}", block.Signature); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /UbudKusCoin/Grpc/TransactionServiceImpl.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Threading.Tasks; 9 | using System; 10 | using Grpc.Core; 11 | using NBitcoin; 12 | using UbudKusCoin.Services; 13 | 14 | namespace UbudKusCoin.Grpc 15 | { 16 | public class TransactionServiceImpl : TransactionService.TransactionServiceBase 17 | { 18 | public override Task GetByHash(Transaction req, ServerCallContext context) 19 | { 20 | var transaction = ServicePool.DbService.TransactionDb.GetByHash(req.Hash); 21 | return Task.FromResult(transaction); 22 | } 23 | 24 | public override Task GetRangeByAddress(TransactionPaging req, ServerCallContext context) 25 | { 26 | var transactions = ServicePool.DbService.TransactionDb.GetRangeByAddress(req.Address, req.PageNumber, req.ResultPerPage); 27 | var response = new TransactionList(); 28 | response.Transactions.AddRange(transactions); 29 | return Task.FromResult(response); 30 | } 31 | 32 | public override Task GetRange(TransactionPaging req, ServerCallContext context) 33 | { 34 | var response = new TransactionList(); 35 | var transactions = ServicePool.DbService.TransactionDb.GetRange(req.PageNumber, req.ResultPerPage); 36 | response.Transactions.AddRange(transactions); 37 | return Task.FromResult(response); 38 | } 39 | 40 | public override Task GetPoolRange(TransactionPaging req, ServerCallContext context) 41 | { 42 | var response = new TransactionList(); 43 | var transactions = ServicePool.DbService.TransactionDb.GetRange(req.PageNumber, req.ResultPerPage); 44 | response.Transactions.AddRange(transactions); 45 | return Task.FromResult(response); 46 | } 47 | 48 | public static bool VerifySignature(Transaction txn) 49 | { 50 | var pubKey = new PubKey(txn.PubKey); 51 | return pubKey.VerifyMessage(txn.Hash, txn.Signature); 52 | } 53 | 54 | public override Task Receive(TransactionPost req, ServerCallContext context) 55 | { 56 | Console.WriteLine("-- Received TXH with hash: {0}, amount {1}", req.Transaction.Hash, req.Transaction.Amount); 57 | 58 | var transactionHash = Others.UkcUtils.GetTransactionHash(req.Transaction); 59 | if (!transactionHash.Equals(req.Transaction.Hash)) 60 | { 61 | return Task.FromResult(new TransactionStatus 62 | { 63 | Status = Others.Constants.TXN_STATUS_FAIL, 64 | Message = "Invalid Transaction Hash" 65 | }); 66 | } 67 | 68 | var isSignatureValid = VerifySignature(req.Transaction); 69 | if (!isSignatureValid) 70 | { 71 | return Task.FromResult(new TransactionStatus 72 | { 73 | Status = Others.Constants.TXN_STATUS_FAIL, 74 | Message = "Invalid Signature" 75 | }); 76 | } 77 | 78 | //TODO add more validation here 79 | 80 | ServicePool.DbService.PoolTransactionsDb.Add(req.Transaction); 81 | return Task.FromResult(new TransactionStatus 82 | { 83 | Status = Others.Constants.TXN_STATUS_SUCCESS, 84 | Message = "Transaction received successfully!" 85 | }); 86 | } 87 | 88 | public override Task Transfer(TransactionPost req, ServerCallContext context) 89 | { 90 | Console.WriteLine("=== Req: {0}", req); 91 | 92 | // Validating hash 93 | var calculateHash = Others.UkcUtils.GetTransactionHash(req.Transaction); 94 | if (!calculateHash.Equals(req.Transaction.Hash)) 95 | { 96 | return Task.FromResult(new TransactionStatus 97 | { 98 | Status = Others.Constants.TXN_STATUS_FAIL, 99 | Message = "Invalid Transaction Hash" 100 | }); 101 | } 102 | 103 | Console.WriteLine("=== CalculateHash: {0}", calculateHash); 104 | 105 | // validating signature 106 | var isSignatureValid = VerifySignature(req.Transaction); 107 | if (!isSignatureValid) 108 | { 109 | return Task.FromResult(new TransactionStatus 110 | { 111 | Status = Others.Constants.TXN_STATUS_FAIL, 112 | Message = "Invalid Signature" 113 | }); 114 | } 115 | 116 | Console.WriteLine("=== isSignatureValid: {0}", isSignatureValid); 117 | 118 | // Check if the transaction is in the pool already 119 | var txinPool = ServicePool.DbService.PoolTransactionsDb.GetByHash(req.Transaction.Hash); 120 | if (txinPool is not null) 121 | { 122 | return Task.FromResult(new TransactionStatus 123 | { 124 | Status = Others.Constants.TXN_STATUS_FAIL, 125 | Message = "Double transaction!" 126 | }); 127 | } 128 | 129 | ServicePool.DbService.PoolTransactionsDb.Add(req.Transaction); 130 | 131 | // broadcast transaction to all peer including myself. 132 | Task.Run(() => ServicePool.P2PService.BroadcastTransaction(req.Transaction)); 133 | 134 | // Response transaction success 135 | return Task.FromResult(new TransactionStatus 136 | { 137 | Status = Others.Constants.TXN_STATUS_SUCCESS, 138 | Message = "Transaction completed!" 139 | }); 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /UbudKusCoin/DB/BlockDb.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using LiteDB; 9 | using UbudKusCoin.Grpc; 10 | using UbudKusCoin.Others; 11 | using System.Collections.Generic; 12 | using System.Linq; 13 | 14 | namespace UbudKusCoin.DB 15 | { 16 | /// 17 | /// Block Database to keep block persistant 18 | /// 19 | public class BlockDb 20 | { 21 | private readonly LiteDatabase _db; 22 | 23 | public BlockDb(LiteDatabase db) 24 | { 25 | _db = db; 26 | } 27 | 28 | /// 29 | /// Add block 30 | /// 31 | public AddBlockStatus Add(Block block) 32 | { 33 | var blocks = GetAll(); 34 | try 35 | { 36 | blocks.Insert(block); 37 | return new AddBlockStatus 38 | { 39 | Status = Constants.TXN_STATUS_SUCCESS, 40 | Message = "Block added successfully" 41 | }; 42 | } 43 | catch 44 | { 45 | return new AddBlockStatus 46 | { 47 | Status = Constants.TXN_STATUS_FAIL, 48 | Message = "Rttpt add transaction to pool" 49 | }; 50 | } 51 | } 52 | 53 | /// 54 | /// Get First Block or Genesis block, ordered by block Height 55 | /// 56 | public Block GetFirst() 57 | { 58 | return GetAll().FindAll().FirstOrDefault(); 59 | } 60 | 61 | /// 62 | /// Get Last block ordered by block weight 63 | /// 64 | public Block GetLast() 65 | { 66 | return GetAll().FindOne(Query.All(Query.Descending)); 67 | } 68 | 69 | /// 70 | /// Get Block by Block weight 71 | /// 72 | public Block GetByHeight(long weight) 73 | { 74 | var blockCollection = GetAll(); 75 | var blocks = blockCollection.Query().Where(x => x.Height == weight).ToList(); 76 | 77 | if (blocks.Any()) 78 | { 79 | return blocks.FirstOrDefault(); 80 | } 81 | 82 | return null; 83 | } 84 | 85 | /// 86 | /// Get Block by block Hash 87 | /// 88 | public Block GetByHash(string hash) 89 | { 90 | var blockCollection = GetAll(); 91 | var blocks = blockCollection.Query().Where(x => x.Hash == hash).ToList(); 92 | 93 | if (blocks.Any()) 94 | { 95 | return blocks.FirstOrDefault(); 96 | } 97 | 98 | return null; 99 | } 100 | 101 | /// 102 | /// Get blocks with paging, page number and number of row per page 103 | /// 104 | public List GetRange(int pageNumber, int resultPerPage) 105 | { 106 | var blockCollection = GetAll(); 107 | 108 | blockCollection.EnsureIndex(x => x.Height); 109 | 110 | var query = blockCollection.Query() 111 | .OrderByDescending(x => x.Height) 112 | .Offset((pageNumber - 1) * resultPerPage) 113 | .Limit(resultPerPage).ToList(); 114 | 115 | return query; 116 | } 117 | 118 | /// 119 | /// Get blocks starting from specific weight until 50 rows 120 | /// 121 | public List GetRemaining(long startHeight) 122 | { 123 | var blockCollection = GetAll(); 124 | 125 | blockCollection.EnsureIndex(x => x.Height); 126 | 127 | var query = blockCollection.Query() 128 | .OrderByDescending(x => x.Height) 129 | .Where(x => x.Height > startHeight && x.Height <= startHeight + 50) 130 | .ToList(); 131 | 132 | return query; 133 | } 134 | 135 | /// 136 | /// Get last blocks 137 | /// 138 | public List GetLast(int num) 139 | { 140 | var blockCollection = GetAll(); 141 | 142 | blockCollection.EnsureIndex(x => x.Height); 143 | 144 | var query = blockCollection.Query() 145 | .OrderByDescending(x => x.Height) 146 | .Limit(num).ToList(); 147 | 148 | return query; 149 | } 150 | 151 | /// 152 | /// Get blocks that validate by address / validator 153 | /// 154 | public IEnumerable GetByValidator(string address, int pageNumber, int resultPerPage) 155 | { 156 | var blockCollection = GetAll(); 157 | 158 | blockCollection.EnsureIndex(x => x.Validator); 159 | 160 | var query = blockCollection.Query() 161 | .OrderByDescending(x => x.Height) 162 | .Where(x => x.Validator == address) 163 | .Offset((pageNumber - 1) * resultPerPage) 164 | .Limit(resultPerPage).ToList(); 165 | 166 | return query; 167 | } 168 | 169 | /// 170 | /// Get all blocks 171 | /// 172 | public ILiteCollection GetAll() 173 | { 174 | var blockCollection = _db.GetCollection(Constants.TBL_BLOCKS); 175 | 176 | blockCollection.EnsureIndex(x => x.Height); 177 | 178 | return blockCollection; 179 | } 180 | 181 | /// 182 | /// Get all hash of all blocks 183 | /// 184 | public IList GetHashList() 185 | { 186 | var blockCollection = GetAll(); 187 | 188 | IList hashList = new List(); 189 | 190 | foreach (var block in blockCollection.FindAll()) 191 | { 192 | hashList.Add(block.Hash); 193 | } 194 | 195 | return hashList; 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /UbudKusCoin/Services/MintingService.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using UbudKusCoin.Grpc; 12 | 13 | namespace UbudKusCoin.Services 14 | { 15 | public class MintingService 16 | { 17 | private CancellationTokenSource cancelTask; 18 | private bool isAlreadyStaking; 19 | private bool isMakingBlock; 20 | private readonly Random rnd; 21 | 22 | public MintingService() 23 | { 24 | rnd = new Random(); 25 | isAlreadyStaking = true; 26 | isMakingBlock = true; 27 | } 28 | 29 | public void Start() 30 | { 31 | // sync state with others 32 | Console.WriteLine(".... Synchronizing state other peer(s) "); 33 | ServicePool.P2PService.SyncState(); 34 | Console.WriteLine(".... Node is Ready."); 35 | 36 | Console.WriteLine("\n.... Minting Service is starting"); 37 | cancelTask = new CancellationTokenSource(); 38 | 39 | // Run Auto Stake, to act as real staking process 40 | // in real blockchain, user will stake through website or mobile app. 41 | // in this auto stake process, I am not do balance validation, 42 | // no signature validation 43 | Task.Run(AutoStake, cancelTask.Token); 44 | 45 | // run minting process 46 | Task.Run(MintingBlock, cancelTask.Token); 47 | } 48 | 49 | public void Stop() 50 | { 51 | cancelTask.Cancel(); 52 | Console.WriteLine("Minter has been stopped"); 53 | } 54 | 55 | public void MintingBlock() 56 | { 57 | isMakingBlock = true; 58 | Console.WriteLine("\n\n= = = = = = = = = = = = NODE IS RUNNING = = = = = = = = = = = =\n"); 59 | Console.WriteLine(". Account Address: {0}", ServicePool.WalletService.GetAddress()); 60 | Console.WriteLine(". Network Address: {0} ", ServicePool.FacadeService.Peer.NodeAddress); 61 | var lastBlock = ServicePool.DbService.BlockDb.GetLast(); 62 | Console.WriteLine("- Last Block: {0}", lastBlock.Height); 63 | Console.WriteLine("\n................ I am ready to validate blocks ..................\n"); 64 | 65 | while (true) 66 | { 67 | var timeMinting = DateTime.UtcNow; 68 | if (timeMinting.Second < 3) 69 | { 70 | isMakingBlock = false; 71 | } 72 | 73 | if (!isMakingBlock && timeMinting.Second >= 45) 74 | { 75 | isMakingBlock = true; 76 | 77 | Console.WriteLine("\n\n= = = = TIME TO MINTING = = = =\n"); 78 | Console.WriteLine("- Time: {0}", timeMinting.Second); 79 | lastBlock = ServicePool.DbService.BlockDb.GetLast(); 80 | Console.WriteLine("- Last Block: {0}", lastBlock.Height); 81 | 82 | Console.WriteLine("\n---------------------------------------------\n Stakes Leaderboard:"); 83 | Task.Run(LeaderBoard); 84 | 85 | var myAddress = ServicePool.WalletService.GetAddress(); 86 | var maxStake = ServicePool.DbService.StakeDb.GetMax(); 87 | if (maxStake is not null && myAddress == maxStake.Address) 88 | { 89 | Console.WriteLine("\n-- Horee, I am the validator of the next block \n"); 90 | ServicePool.FacadeService.Block.New(maxStake); 91 | } 92 | else 93 | { 94 | Console.WriteLine("\n-- Damn, I was not lucky this time. \n"); 95 | } 96 | 97 | Console.WriteLine("= = = = Minting finish = = = \n\n\n"); 98 | } 99 | 100 | // sleep 1 second 101 | Thread.Sleep(1000); 102 | } 103 | } 104 | 105 | /// 106 | /// To send staking one time, before time to create block. 107 | /// 108 | public void AutoStake() 109 | { 110 | ServicePool.DbService.StakeDb.DeleteAll(); 111 | while (true) 112 | { 113 | var timeStaking = DateTime.UtcNow; 114 | // Clean the stakes before create a block. 115 | if (timeStaking.Second < 3) 116 | { 117 | ServicePool.DbService.StakeDb.DeleteAll(); 118 | Console.WriteLine("... I've cleaned my stakes list."); 119 | isAlreadyStaking = false; 120 | Thread.Sleep(4000); 121 | timeStaking = DateTime.UtcNow; 122 | } 123 | 124 | // staking will do in limited time starting from second: 4 to 30 125 | if (!isAlreadyStaking && timeStaking.Second < 35) 126 | { 127 | // Make stakeing with random amount 128 | var stake = new Stake 129 | { 130 | Address = ServicePool.WalletService.GetAddress(), 131 | Amount = rnd.Next(10, 100), 132 | TimeStamp = Others.UkcUtils.GetTime() 133 | }; 134 | Console.WriteLine("... Now I wil stake {0} coins at: {1}\n", stake.Amount, DateTime.UtcNow); 135 | 136 | ServicePool.DbService.StakeDb.AddOrUpdate(stake); 137 | 138 | Task.Run(() => ServicePool.P2PService.BroadcastStake(stake)); 139 | 140 | isAlreadyStaking = true; 141 | } 142 | 143 | // sleep 1 second 144 | Thread.Sleep(1000); 145 | } 146 | } 147 | 148 | private void LeaderBoard() 149 | { 150 | var stakeList = ServicePool.DbService.StakeDb.GetAll().FindAll(); 151 | foreach (var stake in stakeList) 152 | { 153 | Console.WriteLine(" {0}, {1}", stake.Address, stake.Amount); 154 | } 155 | 156 | Console.WriteLine("-----------------------------------------------\n"); 157 | } 158 | } 159 | } -------------------------------------------------------------------------------- /UbudKusCoin/Facade/BlockFacade.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text.Json; 12 | using UbudKusCoin.Grpc; 13 | using UbudKusCoin.Others; 14 | using UbudKusCoin.Services; 15 | using System.Threading.Tasks; 16 | 17 | namespace UbudKusCoin.Facade 18 | { 19 | public class BlockFacade 20 | { 21 | //minter will selected by random 22 | private readonly Random rnd; 23 | 24 | public BlockFacade() 25 | { 26 | rnd = new Random(); 27 | 28 | Initialize(); 29 | Console.WriteLine("...... Block innitialized."); 30 | } 31 | 32 | private void Initialize() 33 | { 34 | var blocks = ServicePool.DbService.BlockDb.GetAll(); 35 | if (blocks.Count() < 1) 36 | { 37 | // create genesis block 38 | CreateGenesis(); 39 | } 40 | } 41 | 42 | /// 43 | /// Create genesis block, the first block in blockchain 44 | /// 45 | public void CreateGenesis() 46 | { 47 | var startTimer = DateTime.UtcNow.Millisecond; 48 | 49 | //Assume Genesis will start on 2022 50 | var genesisTicks = new DateTime(2022, 5, 29).Ticks; 51 | long epochTicks = new DateTime(1970, 1, 1).Ticks; 52 | long timeStamp = (genesisTicks - epochTicks) / TimeSpan.TicksPerSecond; 53 | 54 | // for genesis bloc we set creator with first of Genesis Account 55 | var genesisAccounts = ServicePool.FacadeService.Account.GetGenesis(); 56 | var nodeAccountAddresss = ServicePool.WalletService.GetAddress(); 57 | 58 | // crate genesis transaction 59 | var genesisTransactions = ServicePool.FacadeService.Transaction.CreateGenesis(); 60 | var block = new Block 61 | { 62 | Height = 1, 63 | TimeStamp = timeStamp, 64 | PrevHash = "-", 65 | Transactions = JsonSerializer.Serialize(genesisTransactions), 66 | Validator = nodeAccountAddresss, 67 | Version = 1, 68 | NumOfTx = genesisTransactions.Count, 69 | TotalAmount = UkcUtils.GetTotalAmount(genesisTransactions), 70 | TotalReward = UkcUtils.GetTotalFees(genesisTransactions), 71 | MerkleRoot = CreateMerkleRoot(genesisTransactions), 72 | ValidatorBalance = 0, 73 | Difficulty = 1, 74 | Nonce = 1 75 | }; 76 | 77 | var blockHash = GetBlockHash(block); 78 | block.Hash = blockHash; 79 | block.Signature = ServicePool.WalletService.Sign(blockHash); 80 | 81 | //block size 82 | block.Size = JsonSerializer.Serialize(block).Length; 83 | 84 | // get build time 85 | var endTimer = DateTime.UtcNow.Millisecond; 86 | block.BuildTime = endTimer - startTimer; 87 | 88 | // update accoiunt table 89 | ServicePool.FacadeService.Account.UpdateBalanceGenesis(genesisTransactions); 90 | 91 | // add genesis block to blockchain 92 | ServicePool.DbService.BlockDb.Add(block); 93 | } 94 | 95 | /// 96 | /// Create new Block 97 | /// 98 | public void New(Stake stake) 99 | { 100 | var startTimer = DateTime.UtcNow.Millisecond; 101 | 102 | // get transaction from pool 103 | var poolTransactions = ServicePool.DbService.PoolTransactionsDb.GetAll(); 104 | var wallet = ServicePool.WalletService; 105 | 106 | // get last block before sleep 107 | var lastBlock = ServicePool.DbService.BlockDb.GetLast(); 108 | var nextHeight = lastBlock.Height + 1; 109 | var prevHash = lastBlock.Hash; 110 | 111 | // var validator = ServicePool.FacadeService.Stake.GetValidator(); 112 | var transactions = ServicePool.FacadeService.Transaction.GetForMinting(nextHeight); 113 | var minterAddress = stake.Address; 114 | var minterBalance = stake.Amount; 115 | var timestamp = UkcUtils.GetTime(); 116 | 117 | var block = new Block 118 | { 119 | Height = nextHeight, 120 | TimeStamp = timestamp, 121 | PrevHash = prevHash, 122 | Transactions = JsonSerializer.Serialize(transactions), 123 | Difficulty = 1, //GetDifficullty(), 124 | Validator = minterAddress, 125 | Version = 1, 126 | NumOfTx = transactions.Count, 127 | TotalAmount = UkcUtils.GetTotalAmount(transactions), 128 | TotalReward = UkcUtils.GetTotalFees(transactions), 129 | MerkleRoot = CreateMerkleRoot(transactions), 130 | ValidatorBalance = minterBalance, 131 | Nonce = rnd.Next(100000), 132 | }; 133 | 134 | var blockHash = GetBlockHash(block); 135 | block.Hash = blockHash; 136 | block.Signature = ServicePool.WalletService.Sign(blockHash); 137 | 138 | UkcUtils.PrintBlock(block); 139 | 140 | //block size 141 | block.Size = JsonSerializer.Serialize(block).Length; 142 | 143 | // get build time 144 | var endTimer = DateTime.UtcNow.Millisecond; 145 | block.BuildTime = (endTimer - startTimer); 146 | 147 | ServicePool.FacadeService.Account.UpdateBalance(transactions); 148 | 149 | // move pool to to transactions db 150 | ServicePool.FacadeService.Transaction.AddBulk(transactions); 151 | 152 | // clear mempool 153 | ServicePool.DbService.PoolTransactionsDb.DeleteAll(); 154 | 155 | //add block to db 156 | ServicePool.DbService.BlockDb.Add(block); 157 | 158 | // broadcast block 159 | Task.Run(() => ServicePool.P2PService.BroadcastBlock(block)); 160 | } 161 | 162 | public string GetBlockHash(Block block) 163 | { 164 | var strSum = block.Version + block.PrevHash + block.MerkleRoot + block.TimeStamp + block.Difficulty + block.Validator; 165 | return UkcUtils.GenHash(strSum); 166 | } 167 | 168 | private string CreateMerkleRoot(List txns) 169 | { 170 | return UkcUtils.CreateMerkleRoot(txns.Select(tx => tx.Hash).ToArray()); 171 | } 172 | 173 | /// 174 | /// When receive a block from peer, validate it before insert to DB 175 | /// 176 | public bool IsValidBlock(Block block) 177 | { 178 | var lastBlock = ServicePool.DbService.BlockDb.GetLast(); 179 | 180 | //compare block height with prev 181 | if (block.Height != (lastBlock.Height + 1)) 182 | { 183 | return false; 184 | } 185 | 186 | //compare block hash with prev block hash 187 | if (block.PrevHash != lastBlock.Hash) 188 | { 189 | return false; 190 | } 191 | 192 | //validate hash 193 | if (block.Hash != GetBlockHash(block)) 194 | { 195 | return false; 196 | } 197 | 198 | //compare timestamp 199 | if (block.TimeStamp <= lastBlock.TimeStamp) 200 | { 201 | return false; 202 | } 203 | 204 | return true; 205 | } 206 | } 207 | } -------------------------------------------------------------------------------- /BlockExplorer/BlockExplorer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Threading.Tasks; 5 | using Newtonsoft.Json; 6 | using static UbudKusCoin.Grpc.TransactionService; 7 | using static UbudKusCoin.Grpc.BlockService; 8 | using static UbudKusCoin.Grpc.AccountService; 9 | using Grpc.Net.Client; 10 | using UbudKusCoin.Grpc; 11 | using UbudKusCoin.BlockExplorer.Others; 12 | 13 | namespace UbudKusCoin.BlockExplorer 14 | { 15 | public class BlockExplorer 16 | { 17 | private readonly AccountServiceClient _accountService; 18 | private readonly BlockServiceClient _blockService; 19 | private readonly TransactionServiceClient _transactionService; 20 | 21 | public BlockExplorer(GrpcChannel channel) 22 | { 23 | _accountService = new AccountServiceClient(channel); 24 | _blockService = new BlockServiceClient(channel); 25 | _transactionService = new TransactionServiceClient(channel); 26 | MenuItem(); 27 | GetInput(); 28 | } 29 | 30 | private void MenuItem() 31 | { 32 | Console.Clear(); 33 | Console.WriteLine("\n\n\n"); 34 | Console.WriteLine(" UBUDKUS COIN EXPLORER "); 35 | Console.WriteLine("============================================================"); 36 | Console.WriteLine(" 1. First Block"); 37 | Console.WriteLine(" 2. Last Block"); 38 | Console.WriteLine(" 3. Show All Block"); 39 | Console.WriteLine(" 9. Exit"); 40 | Console.WriteLine("------------------------------------------------------------"); 41 | } 42 | 43 | private void GetInput() 44 | { 45 | int selection = 0; 46 | while (selection != 20) 47 | { 48 | switch (selection) 49 | { 50 | case 1: 51 | ShowFirstBlock(); 52 | 53 | break; 54 | case 2: 55 | ShowLastBlock(); 56 | 57 | break; 58 | 59 | case 3: 60 | ShowAllBlocks(); 61 | break; 62 | 63 | case 9: 64 | Exit(); 65 | break; 66 | } 67 | 68 | if (selection != 0) 69 | { 70 | Console.WriteLine("\n===== Press enter to continue! ====="); 71 | string strKey = Console.ReadLine(); 72 | if (strKey != null) 73 | { 74 | Console.Clear(); 75 | MenuItem(); 76 | } 77 | } 78 | 79 | Console.WriteLine("\n**** Please select menu!!! *****"); 80 | 81 | string action = Console.ReadLine(); 82 | if (!int.TryParse(action, out selection)) 83 | { 84 | selection = 0; 85 | Console.Clear(); 86 | MenuItem(); 87 | } 88 | } 89 | } 90 | 91 | private void ShowLastBlock() 92 | { 93 | try 94 | { 95 | Console.Clear(); 96 | Console.WriteLine("\n\n\n\nLast Block"); 97 | Console.WriteLine("- Time: {0}", DateTime.Now); 98 | Console.WriteLine("======================"); 99 | 100 | var block = _blockService.GetLast(new EmptyRequest()); 101 | PrintBlock(block); 102 | 103 | Console.WriteLine("--------------\n"); 104 | } 105 | catch 106 | { 107 | Console.WriteLine(" error!, {0}", "Please check the UbudKusCoin node. It needs to be running!"); 108 | } 109 | } 110 | 111 | private void ShowFirstBlock() 112 | { 113 | Console.Clear(); 114 | Console.WriteLine("\n\n\n\nGenesis Block"); 115 | Console.WriteLine("Time: {0}", DateTime.Now); 116 | Console.WriteLine("======================"); 117 | 118 | try 119 | { 120 | var block = _blockService.GetFirst(new EmptyRequest()); 121 | 122 | PrintBlock(block); 123 | 124 | Console.WriteLine("--------------\n"); 125 | } 126 | catch 127 | { 128 | Console.WriteLine(" error!, {0}", "Please check the UbudKusCoin node. It needs to be running!"); 129 | } 130 | } 131 | 132 | private static void PrintBlock(Block block) 133 | { 134 | Console.WriteLine("Height : {0}", block.Height); 135 | Console.WriteLine("Version : {0}", block.Version); 136 | Console.WriteLine("Timestamp : {0}", Utils.ToDateTime(block.TimeStamp)); 137 | Console.WriteLine("Hash : {0}", block.Hash); 138 | Console.WriteLine("Merkle Hash : {0}", block.MerkleRoot); 139 | Console.WriteLine("Prev. Hash : {0}", block.PrevHash); 140 | Console.WriteLine("Validator : {0}", block.Validator); 141 | Console.WriteLine("Difficulty : {0}", block.Difficulty); 142 | Console.WriteLine("Num of Txs : {0}", block.NumOfTx); 143 | Console.WriteLine("Total Amount : {0}", block.TotalAmount); 144 | Console.WriteLine("Total Fee : {0}", block.TotalReward); 145 | Console.WriteLine("Size : {0}", block.Size); 146 | Console.WriteLine("Build Time : {0}", block.BuildTime); 147 | 148 | var transactions = JsonConvert.DeserializeObject>(block.Transactions); 149 | Console.WriteLine("Transactions: "); 150 | foreach (var Txn in transactions) 151 | { 152 | Console.WriteLine(" ID : {0}", Txn.Hash); 153 | Console.WriteLine(" Timestamp : {0}", Utils.ToDateTime(Txn.TimeStamp)); 154 | Console.WriteLine(" Sender : {0}", Txn.Sender); 155 | Console.WriteLine(" Recipient : {0}", Txn.Recipient); 156 | Console.WriteLine(" Amount : {0}", Txn.Amount.ToString("N", CultureInfo.InvariantCulture)); 157 | Console.WriteLine(" Fee : {0}", Txn.Fee.ToString("N4", CultureInfo.InvariantCulture)); 158 | Console.WriteLine(" - - - - - - "); 159 | } 160 | } 161 | 162 | private static async void Exit() 163 | { 164 | Console.Clear(); 165 | Console.WriteLine("\n\nApplication closed!\n"); 166 | await Task.Delay(2000); 167 | Environment.Exit(0); 168 | } 169 | 170 | private void ShowAllBlocks() 171 | { 172 | Console.Clear(); 173 | Console.WriteLine("\n\n\nBlockchain Explorer"); 174 | Console.WriteLine("Time: {0}", DateTime.Now); 175 | Console.WriteLine("======================"); 176 | Console.WriteLine("\nPlease enter the page number!:"); 177 | 178 | // validate input 179 | string strPageNumber = Console.ReadLine(); 180 | if (string.IsNullOrWhiteSpace(strPageNumber)) 181 | { 182 | Console.WriteLine("\n\nError, Please input the page number!\n"); 183 | return; 184 | } 185 | 186 | if (!int.TryParse(strPageNumber, out var pageNumber)) 187 | { 188 | Console.WriteLine("\n\nError, page is not a number!\n"); 189 | return; 190 | } 191 | 192 | try 193 | { 194 | var response = _blockService.GetRange(new BlockParams 195 | { 196 | PageNumber = pageNumber, 197 | ResultPerPage = 5 198 | }); 199 | 200 | foreach (var block in response.Blocks) 201 | { 202 | PrintBlock(block); 203 | Console.WriteLine("--------------\n"); 204 | } 205 | } 206 | catch 207 | { 208 | Console.WriteLine(" error!, {0}", "Please check the UbudKusCoin node, it needs to be running!"); 209 | } 210 | } 211 | } 212 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UbudKusCoin 2 | Simple Cryptocurrencies with Proof Of Stake Consensus Algorithm. 3 | 4 | The Blockchain Explorer for this Blockhain can found here: https://github.com/jhonkus/UbudKusCoin-explorer-web 5 | 6 | WHAT NEW 23 Feb 2022 7 | - Support Mnemonic 12 words 8 | - Address with base 58 9 | - P2P with Grpc 10 | 11 | 12 | Articles for This Project: 13 | 14 | - Part 1 15 | 16 | https://putukusuma.medium.com/developing-simple-crypto-application-using-c-48258c2d4e45 17 | 18 | - part 2 19 | 20 | https://putukusuma.medium.com/creating-simple-cryptocurrency-using-c-and-net-core-part-2-menu-and-database-4ae842098f55 21 | 22 | - Part3 23 | 24 | https://putukusuma.medium.com/creating-simple-cryptocurrency-using-c-and-net-core-part-3-wallet-8bbfe0544770 25 | 26 | - Part4 27 | 28 | https://putukusuma.medium.com/creating-simple-cryptocurrency-using-c-and-net-part-4-block-header-c8ad97fd237b 29 | 30 | 31 | - Part5 32 | https://putukusuma.medium.com/creating-simple-cryptocurrency-part-5-peer-to-peer-p2p-with-grpc-f96913ddd7dd 33 | 34 | 35 | Videos: 36 | 37 | - https://youtu.be/TYM55x7I8us 38 | 39 | - https://youtu.be/gpYKUWGBxf4 40 | 41 | - https://youtu.be/tAJKbySs9JY 42 | 43 | 44 | 45 | 46 | Developed with C# and .Net Core 5.0 47 | 48 | This Solution have 3 projects 49 | 50 | - UbudKusCoin is Blockchain Core 51 | - ConsoleWallet is desktop wallet 52 | - BlockExporer is desktop explorer 53 | 54 | 55 | ### Requirement 56 | Net SDK 5.0 https://dotnet.microsoft.com/download/dotnet/5.0 57 | 58 | ### How Install Net SDK 5.0 59 | - download https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-5.0.100-linux-x64-binaries 60 | - cd ~/Downloads (assume the sdk downloaded in Downloads folter) 61 | - mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-5.0.100-linux-x64.tar.gz -C $HOME/dotnet 62 | - export DOTNET_ROOT=$HOME/dotnet 63 | - export PATH=$PATH:$HOME/dotnet 64 | 65 | ### IDE 66 | - Visual Studio Comunity Edition https://visualstudio.microsoft.com/downloads 67 | - For linux user VSCode, follow instruction in this website https://code.visualstudio.com/docs/languages/dotnet 68 | 69 | 70 | ### Instalation 71 | 72 | Afer install .Net Core SDK 5.0 and Visual Studio Code, do next step 73 | 74 | Clone repository 75 | 76 | ``` 77 | > git clone https://github.com/jhonkus/UbudKusCoin.git 78 | 79 | > cd UbudKusCoin 80 | 81 | > dotnet restore 82 | 83 | ``` 84 | 85 | ### Build project to produce binnary files. 86 | 87 | The binnary files can copy to the some folder to easy test P2P and Proof of Stake 88 | 89 | build for linux: 90 | 91 | ``` 92 | dotnet publish -c Release -r linux-x64 -o ./publish-linux 93 | ``` 94 | 95 | Build for macosx 96 | ``` 97 | dotnet publish -c Release -r osx-x64 -o ./publish-osx 98 | ``` 99 | 100 | Build for windows 101 | ``` 102 | dotnet publish -c Release -r win-x64 -o ./publish-win64 103 | ``` 104 | 105 | #### Create 4 folder and Copy binnary files to the folder 106 | ``` 107 | mkdir NODES 108 | cd NODES 109 | mkdir node1 110 | mkdir node2 111 | mkdir node3 112 | mkdir node4 113 | ``` 114 | 115 | #### Copy binnary files to each folders, here i use linux 116 | 117 | ``` 118 | cp publish-linux/* -d ~/NODES/node1 119 | cp publish-linux/* -d ~/NODES/node2 120 | cp publish-linux/* -d ~/NODES/node3 121 | cp publish-linux/* -d ~/NODES/node4 122 | ``` 123 | 124 | #### Copy .env* files to each folder and rename it to .env 125 | ``` 126 | cp env-examples/.env1 ~/NODES/node1/.env 127 | cp env-examples/.env2 ~/NODES/node2/.env 128 | cp env-examples/.env3 ~/NODES/node3/.env 129 | cp env-examples/.env4 ~/NODES/node4/.env 130 | ``` 131 | 132 | 133 | until here you have 4 folder and each folder hamve .env file 134 | each .env file have diffrent values. 135 | 136 | 137 | ### Run all nodes 138 | 139 | Run node1 140 | ``` 141 | > cd NODES/node1 142 | > ./UbudKusCoin 143 | ``` 144 | wait until node1 generate some blocks, let's saya 5 blocks 145 | 146 | 147 | Run node2 148 | Open new terminal 149 | 150 | ``` 151 | > cd NODES/node2 152 | > ./UbudKusCoin 153 | ``` 154 | 155 | See on the console of node2, node2 will download blocks from node1 156 | both node1 and node2 will do minting and do staking. 157 | and one of them will make blokcs. 158 | 159 | 160 | Run node3 161 | Open new terminal 162 | 163 | ``` 164 | > cd NODES/node3 165 | > ./UbudKusCoin 166 | ``` 167 | 168 | See on the console of node3, node3 will download blocks from node1 169 | and node2, 170 | All 3 nodes: node1, node2 and node3 will do minting and do staking. 171 | and one of them will make blokcs. 172 | 173 | 174 | 175 | Run node4 176 | Open new terminal 177 | 178 | ``` 179 | > cd NODES/node4 180 | > ./UbudKusCoin 181 | ``` 182 | 183 | See on the console of node4, node4 will download blocks from node1, node2 and node3. 184 | All 4 nodes: node1, node2, node3 and node4 will do minting and do staking. 185 | and one of them will make blokcs. 186 | 187 | 188 | Any question please put on github issues. 189 | 190 | 191 | 192 | To run BlockExplorer 193 | 194 | ``` 195 | > cd BlockExplorer 196 | > dotnet run 197 | 198 | ``` 199 | 200 | To run ConsoleWallet 201 | 202 | ``` 203 | > cd ConsoleWallet 204 | > dotnet run 205 | 206 | ``` 207 | 208 | Restore Genesis Account Console Wallet 209 | 210 | - Select menu no 2 restore account 211 | - input this: 37115820268057954843929458901983051845242353300769768346456079873593606626394 212 | 213 | 214 | ## Edit Project 215 | 216 | Open Project with Visual Studio Code. 217 | 218 | 219 | ## Build project for Publish 220 | 221 | - Net Runtime 222 | 223 | ``` 224 | dotnet publish -c Release -o ./publish-net 225 | ``` 226 | 227 | 228 | ## Deploy UbudKusCoin on AWS Lightstall or other vps linux 229 | 230 | - Connect to linux vps with ssh client 231 | ``` 232 | ssh -i ~/SSH/ssh.pem your-user@your-IP (y~/SSH/ssh.pem is path of your private key) 233 | ``` 234 | 235 | - Download and install .net core sdk5.0 on vps 236 | ``` 237 | wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-linux-x64.tar.gz 238 | 239 | ls (make sure the file dotnet-sdk-5.0.100-linux-x64.tar.gz exist) 240 | 241 | mkdir -p $HOME/dotnet (create folder dotnet) 242 | 243 | tar zxf dotnet-sdk-5.0.100-linux-x64.tar.gz -C $HOME/dotnet (unzip the file to dotnet folder) 244 | 245 | ls $HOME/dotnet (make sure unzip result exist) 246 | 247 | ``` 248 | 249 | - Set PATH for dotnet sdk on vps 250 | ``` 251 | nano ~/.bashrc (or your profile file) 252 | ``` 253 | 254 | - Add this 2 lines at the end of your bashrc profile 255 | 256 | ``` 257 | export DOTNET_ROOT=$HOME/dotnet 258 | export PATH=$PATH:$HOME/dotnet 259 | ``` 260 | 261 | - save your bash profile buy press ctrl+x and yes in your keyboard 262 | 263 | 264 | - activate your bash profile 265 | ``` 266 | source ~/.bashrc 267 | ``` 268 | 269 | - Create folder ukc on vps server 270 | 271 | ``` 272 | mkdir $HOME/ukc 273 | ``` 274 | 275 | 276 | - Open other terminal in your Laptop/PC and build UbudKusCoin for linux 277 | 278 | ``` 279 | cd UbudKusCoin/UbudKusCoin 280 | dotnet publish -c Release -r linux-x64 -o ./publish-linux 281 | ``` 282 | 283 | - Zip all files of build result 284 | build result take location in publish-linux folder 285 | ``` 286 | cd publish-linux 287 | zip -r archive.zip . (with dot at the end) 288 | ``` 289 | 290 | 291 | - Copy file to vps (virtual private server) 292 | ``` 293 | scp -i ~/SSH/ssh.pem archive.zip root@xxx.xxx.xxx.xxx:~/ukc 294 | ``` 295 | 296 | - Unzip archive.zip on your vps server 297 | - connect to your vps again, see above command to connect to your vps 298 | 299 | ``` 300 | cd ~/ukc 301 | unzip archive.zip 302 | ``` 303 | 304 | - run ukc core 305 | ``` 306 | ~/ukc/UbudKusCoin 307 | ``` 308 | ubudkus coin core will run, but when terminal closed, it will stoped, follow next step 309 | how run ubudkuscoin as service 310 | 311 | - Open/allow Port 5002 in your firewall setting, so it can access from client side. in aws lightsaill, there is network menu, edit it. 312 | 313 | 314 | ## Run as service on linux vps 315 | 316 | - copy/upload file UbudKusCoin.service to vps folder 317 | /etc/systemd/system 318 | 319 | so location will be /etc/systemd/system/UbudKusCoin.service 320 | 321 | 322 | - Start the service 323 | 324 | ``` 325 | sudo systemctl daemon-reload 326 | sudo systemctl start UbudKusCoin 327 | sudo systemctl enable UbudKusCoin 328 | 329 | 330 | ``` 331 | - Stop the service 332 | 333 | ``` 334 | sudo systemctl stop UbudKusCoin 335 | 336 | ``` 337 | 338 | 339 | for more detail see end of this file 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | Please read this articles to know more detail how to run app as service on linux 349 | 350 | References: 351 | 352 | - https://docs.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/self-hosted 353 | 354 | 355 | - https://stackoverflow.com/questions/63827667/bind-grpc-services-to-specific-port-in-aspnetcore 356 | 357 | - https://swimburger.net/blog/dotnet/how-to-run-a-dotnet-core-console-app-as-a-service-using-systemd-on-linux 358 | 359 | - https://docs.microsoft.com/en-us/aspnet/core/grpc/browser?view=aspnetcore-6.0#configure-grpc-web-in-aspnet-core 360 | 361 | - https://docs.microsoft.com/en-us/aspnet/core/grpc/browser?view=aspnetcore-6.0 362 | 363 | - .Net Core with TLS 364 | https://andrewlock.net/creating-and-trusting-a-self-signed-certificate-on-linux-for-use-in-kestrel-and-asp-net-core/ 365 | 366 | 367 | 368 | -------------------------------------------------------------------------------- /UbudKusCoin/P2P/P2PService.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System.Linq; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Threading.Tasks; 12 | using UbudKusCoin.Grpc; 13 | using UbudKusCoin.Services; 14 | using Grpc.Net.Client; 15 | using static UbudKusCoin.Grpc.PeerService; 16 | using static UbudKusCoin.Grpc.BlockService; 17 | using static UbudKusCoin.Grpc.TransactionService; 18 | using static UbudKusCoin.Grpc.StakeService; 19 | 20 | namespace UbudKusCoin.P2P 21 | { 22 | /// 23 | /// This class for communicating with other peer, such as to broadcasting block, 24 | /// broadcasting transaction, downloading block. 25 | /// 26 | public class P2PService 27 | { 28 | public P2PService() 29 | { 30 | } 31 | 32 | public void Start() 33 | { 34 | Console.WriteLine("... P2P service is starting"); 35 | // do some task 36 | Console.WriteLine("...... P2P service is ready"); 37 | } 38 | 39 | 40 | /// 41 | /// Do Braodcast a block to all peer in known peers 42 | /// 43 | /// 44 | public void BroadcastBlock(Block block) 45 | { 46 | var knownPeers = ServicePool.FacadeService.Peer.GetKnownPeers(); 47 | var nodeAddress = ServicePool.FacadeService.Peer.NodeAddress; 48 | 49 | Parallel.ForEach(knownPeers, peer => 50 | { 51 | if (!nodeAddress.Equals(peer.Address)) 52 | { 53 | Console.WriteLine("-- BroadcastBlock to {0}", peer.Address); 54 | GrpcChannel channel = GrpcChannel.ForAddress(peer.Address); 55 | var blockService = new BlockServiceClient(channel); 56 | try 57 | { 58 | var response = blockService.Add(block); 59 | Console.WriteLine("--- Done "); 60 | } 61 | catch 62 | { 63 | Console.WriteLine("--- Fail "); 64 | } 65 | } 66 | }); 67 | } 68 | 69 | 70 | /// 71 | /// Do Broadcast a stake to all peer in known peers 72 | /// 73 | /// 74 | public void BroadcastStake(Stake stake) 75 | { 76 | var knownPeers = ServicePool.FacadeService.Peer.GetKnownPeers(); 77 | var nodeAddress = ServicePool.FacadeService.Peer.NodeAddress; 78 | Parallel.ForEach(knownPeers, peer => 79 | { 80 | if (!nodeAddress.Equals(peer.Address)) 81 | { 82 | Console.WriteLine("-- BroadcastStake to {0}", peer.Address); 83 | GrpcChannel channel = GrpcChannel.ForAddress(peer.Address); 84 | var stakeService = new StakeServiceClient(channel); 85 | try 86 | { 87 | var response = stakeService.Add(stake); 88 | Console.WriteLine("--- Done"); 89 | } 90 | catch 91 | { 92 | Console.WriteLine("--- Fail"); 93 | } 94 | } 95 | }); 96 | } 97 | 98 | /// 99 | /// Do broadcast a transaction to all peer in known peers 100 | /// 101 | /// 102 | public void BroadcastTransaction(Transaction tx) 103 | { 104 | var knownPeers = ServicePool.FacadeService.Peer.GetKnownPeers(); 105 | var nodeAddress = ServicePool.FacadeService.Peer.NodeAddress; 106 | Parallel.ForEach(knownPeers, peer => 107 | { 108 | if (!nodeAddress.Equals(peer.Address)) 109 | { 110 | Console.WriteLine("-- BroadcastTransaction to {0}", peer.Address); 111 | GrpcChannel channel = GrpcChannel.ForAddress(peer.Address); 112 | var txnService = new TransactionServiceClient(channel); 113 | try 114 | { 115 | var response = txnService.Receive(new TransactionPost 116 | { 117 | SendingFrom = nodeAddress, 118 | Transaction = tx 119 | }); 120 | if (response.Status == Others.Constants.TXN_STATUS_SUCCESS) 121 | { 122 | Console.WriteLine(".. Done"); 123 | } 124 | else 125 | { 126 | Console.WriteLine(".. Fail"); 127 | } 128 | } 129 | catch 130 | { 131 | Console.WriteLine(".. Fail"); 132 | } 133 | } 134 | }); 135 | } 136 | 137 | 138 | /// 139 | /// Sincronizing blocks from all peer in known peers 140 | /// 141 | /// 142 | /// 143 | /// 144 | private void DownloadBlocks(BlockServiceClient blockService, long lastBlockHeight, long peerHeight) 145 | { 146 | var response = blockService.GetRemains(new StartingParam { Height = lastBlockHeight }); 147 | List blocks = response.Blocks.ToList(); 148 | blocks.Reverse(); 149 | 150 | var lastHeight = 0L; 151 | foreach (var block in blocks) 152 | { 153 | try 154 | { 155 | Console.WriteLine("==== Download block: {0}", block.Height); 156 | var status = ServicePool.DbService.BlockDb.Add(block); 157 | lastHeight = block.Height; 158 | Console.WriteLine("==== Done"); 159 | } 160 | catch 161 | { 162 | Console.WriteLine("==== Fail"); 163 | } 164 | } 165 | 166 | if (lastHeight < peerHeight) 167 | { 168 | DownloadBlocks(blockService, lastHeight, peerHeight); 169 | } 170 | } 171 | 172 | /// 173 | /// Checking in db if new peer already in DB 174 | /// 175 | /// 176 | /// 177 | private bool IsNewPeer(string address) 178 | { 179 | var knownPeers = ServicePool.FacadeService.Peer.GetKnownPeers(); 180 | foreach (var peer in knownPeers) 181 | { 182 | if (address == peer.Address) 183 | { 184 | return true; 185 | } 186 | } 187 | 188 | return false; 189 | } 190 | 191 | 192 | /// 193 | /// Sincronize blockchain states, make block height same with other peer 194 | /// 195 | public void SyncState() 196 | { 197 | var knownPeers = ServicePool.FacadeService.Peer.GetKnownPeers(); 198 | var nodeAddress = ServicePool.FacadeService.Peer.NodeAddress; 199 | 200 | //synchronizing peer 201 | foreach (var peer in knownPeers) 202 | { 203 | if (!nodeAddress.Equals(peer.Address)) 204 | { 205 | Console.WriteLine("Sync state to {0}", peer.Address); 206 | try 207 | { 208 | GrpcChannel channel = GrpcChannel.ForAddress(peer.Address); 209 | var peerService = new PeerServiceClient(channel); 210 | var peerState = peerService.GetNodeState(new NodeParam { NodeIpAddress = nodeAddress }); 211 | 212 | // add peer to db 213 | foreach (var newPeer in peerState.KnownPeers) 214 | { 215 | ServicePool.FacadeService.Peer.Add(newPeer); 216 | } 217 | } 218 | catch 219 | { 220 | } 221 | } 222 | } 223 | 224 | // synchronizing blocks 225 | knownPeers = ServicePool.FacadeService.Peer.GetKnownPeers(); 226 | foreach (var peer in knownPeers) 227 | { 228 | if (!nodeAddress.Equals(peer.Address)) 229 | { 230 | try 231 | { 232 | GrpcChannel channel = GrpcChannel.ForAddress(peer.Address); 233 | var peerService = new PeerServiceClient(channel); 234 | var peerState = peerService.GetNodeState(new NodeParam { NodeIpAddress = nodeAddress }); 235 | 236 | // local block height 237 | var lastBlockHeight = ServicePool.DbService.BlockDb.GetLast().Height; 238 | var blockService = new BlockServiceClient(channel); 239 | if (lastBlockHeight < peerState.Height) 240 | { 241 | DownloadBlocks(blockService, lastBlockHeight, peerState.Height); 242 | } 243 | } 244 | catch 245 | { 246 | } 247 | } 248 | } 249 | 250 | Console.WriteLine("---- Sync Done~"); 251 | } 252 | } 253 | } -------------------------------------------------------------------------------- /ConsoleWallet/ConsoleAppWallet.cs: -------------------------------------------------------------------------------- 1 | // Created by I Putu Kusuma Negara 2 | // markbrain2013[at]gmail.com 3 | // 4 | // Ubudkuscoin is free software distributed under the MIT software license, 5 | // Redistribution and use in source and binary forms with or without 6 | // modifications are permitted. 7 | 8 | using System; 9 | using System.Globalization; 10 | using System.Threading.Tasks; 11 | using UbudKusCoin.Grpc; 12 | using static UbudKusCoin.Grpc.TransactionService; 13 | using static UbudKusCoin.Grpc.BlockService; 14 | using static UbudKusCoin.Grpc.AccountService; 15 | using Grpc.Net.Client; 16 | 17 | namespace UbudKusCoin.ConsoleWallet 18 | { 19 | public class ConsoleAppWallet 20 | { 21 | private readonly AccountServiceClient _accountService; 22 | private readonly BlockServiceClient _blockService; 23 | private readonly TransactionServiceClient _transactionService; 24 | 25 | private Wallet _accountExt; 26 | 27 | public ConsoleAppWallet(GrpcChannel channel) 28 | { 29 | _accountService = new AccountServiceClient(channel); 30 | _blockService = new BlockServiceClient(channel); 31 | _transactionService = new TransactionServiceClient(channel); 32 | MenuItem(); 33 | GetInput(); 34 | } 35 | 36 | private void MenuItem() 37 | { 38 | if (_accountExt == null) 39 | { 40 | Console.Clear(); 41 | Console.WriteLine("\n\n\n"); 42 | Console.WriteLine(" UBUDKUS COIN WALLET "); 43 | Console.WriteLine("============================================================"); 44 | Console.WriteLine(" Address: - "); 45 | Console.WriteLine("============================================================"); 46 | Console.WriteLine(" 1. Create Account"); 47 | Console.WriteLine(" 2. Restore Account"); 48 | Console.WriteLine(" 9. Exit"); 49 | Console.WriteLine("------------------------------------------------------------"); 50 | } 51 | else 52 | { 53 | Console.Clear(); 54 | Console.WriteLine("\n\n\n"); 55 | Console.WriteLine(" UBUDKUS COIN WALLET "); 56 | Console.WriteLine("============================================================"); 57 | Console.WriteLine(" Address: {0}", _accountExt.GetAddress()); 58 | Console.WriteLine("============================================================"); 59 | Console.WriteLine(" 1. Create Account"); 60 | Console.WriteLine(" 2. Restore Account"); 61 | Console.WriteLine(" 3. Send Coin"); 62 | Console.WriteLine(" 4. Check Balance"); 63 | Console.WriteLine(" 5. Transaction History"); 64 | Console.WriteLine(" 6. Account Info"); 65 | Console.WriteLine(" 7. Send Bulk Tx"); 66 | Console.WriteLine(" 9. Exit"); 67 | Console.WriteLine("------------------------------------------------------------"); 68 | } 69 | } 70 | 71 | private void GetInput() 72 | { 73 | int selection = 0; 74 | while (selection != 20) 75 | { 76 | switch (selection) 77 | { 78 | case 1: 79 | DoCreateAccount(); 80 | break; 81 | case 2: 82 | DoRestore(); 83 | break; 84 | case 3: 85 | DoSendCoin(); 86 | break; 87 | case 4: 88 | DoGetBalance(); 89 | break; 90 | case 5: 91 | DoGetTransactionHistory(); 92 | break; 93 | case 6: 94 | DoShowAccountInfo(); 95 | break; 96 | case 7: 97 | DoSendBulkTx(); 98 | break; 99 | case 9: 100 | DoExit(); 101 | break; 102 | } 103 | 104 | if (selection != 0) 105 | { 106 | Console.WriteLine("\n===== Press enter to continue! ====="); 107 | string strKey = Console.ReadLine(); 108 | if (!string.IsNullOrWhiteSpace(strKey)) 109 | { 110 | Console.Clear(); 111 | MenuItem(); 112 | } 113 | } 114 | 115 | Console.WriteLine("\n**** Please select a menu item!!! *****"); 116 | string action = Console.ReadLine(); 117 | if (!int.TryParse(action, out selection)) 118 | { 119 | selection = 0; 120 | Console.Clear(); 121 | MenuItem(); 122 | } 123 | } 124 | } 125 | 126 | private void DoSendBulkTx() 127 | { 128 | Console.Clear(); 129 | Console.WriteLine("\n\n\n\nTransfer Coin"); 130 | Console.WriteLine("Time: {0}", DateTime.Now); 131 | Console.WriteLine("======================"); 132 | 133 | Console.WriteLine("Sender address:"); 134 | string sender = _accountExt.GetAddress(); 135 | Console.WriteLine(sender); 136 | 137 | Console.WriteLine("\nPlease enter the recipient address!:"); 138 | string recipient = Console.ReadLine(); 139 | 140 | Console.WriteLine("\nPlease enter the number of Tx!:"); 141 | string strNumOfTx = Console.ReadLine(); 142 | 143 | double amount = 0.0001d; 144 | float fee = 0.0001f; 145 | 146 | if (string.IsNullOrEmpty(sender) || 147 | string.IsNullOrEmpty(strNumOfTx) || 148 | string.IsNullOrEmpty(recipient)) 149 | { 150 | Console.WriteLine("\n\nError, Please input all data: sender, recipient, amount and fee!\n"); 151 | return; 152 | } 153 | 154 | var response = _accountService.GetByAddress(new Account()); 155 | var senderBalance = response.Balance; 156 | var numOfTx = int.Parse(strNumOfTx); 157 | 158 | if ((numOfTx * amount + fee) > senderBalance) 159 | { 160 | Console.WriteLine("\nError! The sender ({0}) does not have enough balance!", sender); 161 | Console.WriteLine("Sender's balance is {0}", senderBalance); 162 | return; 163 | } 164 | 165 | for (int i = 0; i < numOfTx; i++) 166 | { 167 | Console.Write(i + "- "); 168 | SendCoin(_accountExt.GetAddress(), recipient, amount, fee); 169 | System.Threading.Thread.Sleep(50); 170 | } 171 | } 172 | 173 | private void SendCoin(string sender, string recipient, double amount, float fee) 174 | { 175 | var newTxn = new Transaction 176 | { 177 | Sender = sender, 178 | TimeStamp = Others.Utils.GetTime(), 179 | Recipient = recipient, 180 | Amount = amount, 181 | Fee = fee, 182 | Height = 0, 183 | TxType = "Transfer", 184 | }; 185 | 186 | var TxnHash = Others.Utils.GetTransactionHash(newTxn); 187 | var signature = _accountExt.Sign(TxnHash); 188 | newTxn.Hash = TxnHash; 189 | newTxn.Signature = signature; 190 | 191 | var transferRequest = new TransactionPost 192 | { 193 | SendingFrom = "Console Wallet", 194 | Transaction = newTxn 195 | }; 196 | 197 | try 198 | { 199 | var transferResponse = _transactionService.Transfer(transferRequest); 200 | if (transferResponse.Status.ToLower() == "success") 201 | { 202 | Console.WriteLine("== Success == "); 203 | } 204 | else 205 | { 206 | Console.WriteLine("Error: {0}", transferResponse.Message); 207 | } 208 | } 209 | catch (Exception e) 210 | { 211 | Console.WriteLine("Error: {0}", e.Message); 212 | } 213 | } 214 | 215 | private void DoShowAccountInfo() 216 | { 217 | WalletInfo(); 218 | } 219 | 220 | private void DoSendCoin() 221 | { 222 | Console.Clear(); 223 | Console.WriteLine("\n\n\n\nTransfer Coin"); 224 | Console.WriteLine("Time: {0}", DateTime.Now); 225 | Console.WriteLine("======================"); 226 | 227 | Console.WriteLine("Sender address:"); 228 | string sender = _accountExt.GetAddress(); 229 | Console.WriteLine(sender); 230 | 231 | Console.WriteLine("\nPlease enter the recipient address!:"); 232 | string recipient = Console.ReadLine(); 233 | 234 | Console.WriteLine("\nPlease enter the amount (number)!:"); 235 | string strAmount = Console.ReadLine(); 236 | 237 | Console.WriteLine("\nPlease enter fee (number)!:"); 238 | string strFee = Console.ReadLine(); 239 | double amount; 240 | 241 | if (string.IsNullOrEmpty(sender) || 242 | string.IsNullOrEmpty(recipient) || 243 | string.IsNullOrEmpty(strAmount) || 244 | string.IsNullOrEmpty(strFee)) 245 | { 246 | Console.WriteLine("\n\nError, Please input all data: sender, recipient, amount and fee!\n"); 247 | return; 248 | } 249 | 250 | if (!double.TryParse(strAmount, out amount)) 251 | { 252 | Console.WriteLine("\nError! You have inputted the wrong value for the amount!"); 253 | return; 254 | } 255 | 256 | if (!float.TryParse(strFee, out var fee)) 257 | { 258 | Console.WriteLine("\nError! You have inputted the wrong value for the fee!"); 259 | return; 260 | } 261 | 262 | var response = _accountService.GetByAddress(new Account 263 | { 264 | Address = sender 265 | }); 266 | 267 | var senderBalance = response.Balance; 268 | 269 | if ((amount + fee) > senderBalance) 270 | { 271 | Console.WriteLine("\nError! Sender ({0}) does not have enough balance!", sender); 272 | Console.WriteLine("Sender balance is {0}", senderBalance); 273 | return; 274 | } 275 | 276 | var NewTxn = new Transaction 277 | { 278 | Sender = _accountExt.GetAddress(), 279 | TimeStamp = Others.Utils.GetTime(), 280 | Recipient = recipient, 281 | Amount = amount, 282 | Fee = fee, 283 | Height = 0, 284 | TxType = "Transfer", 285 | PubKey = _accountExt.GetKeyPair().PublicKeyHex, 286 | }; 287 | 288 | var TxnHash = Others.Utils.GetTransactionHash(NewTxn); 289 | var signature = _accountExt.Sign(TxnHash); 290 | 291 | NewTxn.Hash = TxnHash; 292 | NewTxn.Signature = signature; 293 | 294 | var transferRequest = new TransactionPost 295 | { 296 | SendingFrom = "Console Wallet", 297 | Transaction = NewTxn 298 | }; 299 | 300 | try 301 | { 302 | var transferResponse = _transactionService.Transfer(transferRequest); 303 | if (transferResponse.Status.ToLower() == "success") 304 | { 305 | DateTime utcDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(Convert.ToDouble(NewTxn.TimeStamp)); 306 | 307 | Console.Clear(); 308 | Console.WriteLine("\n\n\n\nTransaction has been sent to the Blockchain!"); 309 | Console.WriteLine("Timestamp: {0}", utcDate.ToLocalTime()); 310 | Console.WriteLine("Sender: {0}", NewTxn.Sender); 311 | Console.WriteLine("Recipient {0}", NewTxn.Recipient); 312 | Console.WriteLine("Amount: {0}", NewTxn.Amount); 313 | Console.WriteLine("Fee: {0}", NewTxn.Fee); 314 | Console.WriteLine("-------------------"); 315 | Console.WriteLine("Please, wait the transaction processing!"); 316 | } 317 | else 318 | { 319 | Console.WriteLine("Error: {0}", transferResponse.Message); 320 | } 321 | } 322 | catch 323 | { 324 | Console.WriteLine("\nError! Please check the UbudKusCoin Node, it needs to be running!"); 325 | } 326 | } 327 | 328 | private void DoRestore() 329 | { 330 | Console.Clear(); 331 | Console.WriteLine("Restore Wallet"); 332 | Console.WriteLine("Please enter 12 words passphrase:"); 333 | 334 | string secret = Console.ReadLine(); 335 | if (string.IsNullOrWhiteSpace(secret)) 336 | { 337 | Console.WriteLine("\n\nError, please input your 12 words passphrase!\n"); 338 | return; 339 | } 340 | 341 | try 342 | { 343 | _accountExt = new Wallet(secret); 344 | WalletInfo(); 345 | } 346 | catch 347 | { 348 | Console.WriteLine("Invalid passphrase!"); 349 | } 350 | } 351 | 352 | private void DoCreateAccount() 353 | { 354 | _accountExt = new Wallet(); 355 | WalletInfo(); 356 | } 357 | 358 | private void WalletInfo() 359 | { 360 | Console.Clear(); 361 | Console.WriteLine("\n\n\nYour Wallet"); 362 | Console.WriteLine("======================"); 363 | Console.WriteLine("\nADDRESS:\n{0}", _accountExt.GetAddress()); 364 | Console.WriteLine("\nPUBLIC KEY:\n{0}", _accountExt.GetKeyPair().PublicKeyHex); 365 | Console.WriteLine("\nPASSPHRASE 12 words:\n{0}", _accountExt.Passphrase); 366 | Console.WriteLine("\n - - - - - - - - - - - - - - - - - - - - - - "); 367 | Console.WriteLine("*** Store your passphrase in a safe place! And please don't tell it to anyone! ***"); 368 | Console.WriteLine("*** If you lose your passphrase, your money will be lost! ***"); 369 | Console.WriteLine("*** Use your secret number to restore your account! ***"); 370 | } 371 | 372 | private static async void DoExit() 373 | { 374 | Console.Clear(); 375 | Console.WriteLine("\n\nApplication closed!\n"); 376 | await Task.Delay(2000); 377 | Environment.Exit(0); 378 | } 379 | 380 | private void DoGetTransactionHistory() 381 | { 382 | string address = _accountExt.GetAddress(); 383 | if (string.IsNullOrWhiteSpace(address)) 384 | { 385 | Console.WriteLine("\n\nError, the address is empty, please create an account first!\n"); 386 | return; 387 | } 388 | 389 | Console.Clear(); 390 | Console.WriteLine("Transaction History for {0}", address); 391 | Console.WriteLine("Time: {0}", DateTime.Now); 392 | Console.WriteLine("======================"); 393 | 394 | try 395 | { 396 | Console.WriteLine("OK"); 397 | 398 | var response = _transactionService.GetRangeByAddress(new TransactionPaging 399 | { 400 | Address = address, 401 | PageNumber = 1, 402 | ResultPerPage = 50 403 | }); 404 | 405 | Console.WriteLine("=== Response"); 406 | 407 | if (response != null && response.Transactions != null) 408 | { 409 | foreach (var Txn in response.Transactions) 410 | { 411 | Console.WriteLine("Hash : {0}", Txn.Hash); 412 | Console.WriteLine("Timestamp : {0}", Others.Utils.ToDateTime(Txn.TimeStamp)); 413 | Console.WriteLine("Sender : {0}", Txn.Sender); 414 | Console.WriteLine("Recipient : {0}", Txn.Recipient); 415 | Console.WriteLine("Amount : {0}", Txn.Amount.ToString("N", CultureInfo.InvariantCulture)); 416 | Console.WriteLine("Fee : {0}", Txn.Fee.ToString("N4", CultureInfo.InvariantCulture)); 417 | Console.WriteLine("--------------\n"); 418 | } 419 | } 420 | else 421 | { 422 | Console.WriteLine("\n---- No records found! ---"); 423 | } 424 | } 425 | catch 426 | { 427 | Console.WriteLine("\nError! Please check your UbudKusCoin Node, it needs to be running!"); 428 | } 429 | } 430 | 431 | private void DoGetBalance() 432 | { 433 | string address = _accountExt.GetAddress(); 434 | if (string.IsNullOrEmpty(address)) 435 | { 436 | Console.WriteLine("\n\nError, the address is empty, please create an account first!\n"); 437 | return; 438 | } 439 | 440 | Console.Clear(); 441 | Console.WriteLine("Balance for {0}", address); 442 | Console.WriteLine("Time: {0}", DateTime.Now); 443 | Console.WriteLine("======================"); 444 | try 445 | { 446 | var response = _accountService.GetByAddress(new Account 447 | { 448 | Address = address 449 | }); 450 | Console.WriteLine("Balance: {0}", response.Balance.ToString("N", CultureInfo.InvariantCulture)); 451 | } 452 | catch 453 | { 454 | Console.WriteLine("\nError! Please check your UbudKusCoin Node, it needs to be running!"); 455 | } 456 | } 457 | } 458 | } --------------------------------------------------------------------------------