├── 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 | }
--------------------------------------------------------------------------------