Browse Source

Build 1.1

Build 1.1 with JSON-RPC server
PascalCoin 8 years ago
parent
commit
f371c4c11c

+ 0 - 135
COMPILE_INSTRUCTIONS.txt

@@ -1,135 +0,0 @@
-*********************************
-*** HOW TO COMPILE PASCALCOIN ***
-*********************************
-(File updated 2016-10-20)
-
-Instruction about how to compile Pascal Coin Wallet 1.0.9  (2016-10-21)
-For newer versions... I hope will be similar ;-)
-
-IMPORTANT NOTE:
-- In Windows, it's tested with XP, W7 and W10.  In Linux, is tested on Ubuntu 16.04.1 (Graphical version) 64 bits
-- In Ubuntu 16.04.1, there is a Lazarus installation issue. See FAQ 01 (at the end of this document)
-
-- You can compile with Delphi (Tested Delphi version 2010), or with Lazarus (Tested version 1.6)
-- Cross-compatible if using Lazarus  (Windows + Linux + Mac)  (Note: Not tested in Mac, only Windows or Ubuntu)
-
-
-PLEASE READ CAREFULLY:
-
-
-**************************
-** DOWNLOAD SOURCE CODE **
-**************************
-
-- Create a source code folder, we will call this folder "SOURCE_CODE_FOLDER" 
-
-- Download PascalCoin source code from: https://github.com/PascalCoin/PascalCoin  (Tested with Build 1.0.9)
-- Download Synapse source code from: http://www.ararat.cz/synapse/lib/exe/fetch.php/file:synapse40.zip  (Tested with version Synapse40)
-  - Also you can download a new version from svn: https://sourceforge.net/p/synalist/code/HEAD/tree/trunk/
-  - If URL is broken, try searching "Synapse ararat" at Google and Download
-
-** WINDOWS **
-- If you want to compile for ** WINDOWS **, oobtain OpenSSL DLL's from: https://indy.fulgan.com/SSL/
-  - If compiler is Delphi, you must obtain a 32 bits DLL file
-  - If compiler is Lazarus, you must obtain a 64 bits DLL file
-  - You must unzip file "libeay32.dll" and put in "SOURCE_CODE_FOLDER"
-  - If you compile with Lazarus, RENAME this file to "libeay64.dll" because is 64 bits version
-
-** LAZARUS **
-- If you want to compile for Lazarus, obtain OpenSSL source code from: https://www.openssl.org/source/
-  - See section ** BUILD OPENSSL FOR LINUX **
-  - Tested with openssl-1.1.0b.targ.gz (2016-Sep-26)  
-
-*************************
-** DOWNLOAD BLOCKCHAIN **
-*************************
-
-- You don't need to obtain Blockchain, but is more quickly if you have downloaded it than to wait App download it from other nodes...
-- You will find a valid BlockChain at SourceForge PascalCoin downloads: https://sourceforge.net/projects/pascalcoin/files/ - Search for "BlockChain" file
-- Blockchain must be unziped and stored at PascalCoin data folder: (We will call it "PASCALCOIN_DATA_FOLDER")
-  - PascalCoin data folder for Windows:   c:\Users\(your user)\AppData\Roaming\PascalCoin\Data
-  - PascalCoin data folder for Linux: /home/(your user)/PascalCoin/Data
-
-REMEMBER TO PUT BLOCKCHAIN IN CORRECT "PASCALCOIN_DATA_FOLDER"
-REMEMBER TO GRANT PERMISIONS TO USER AT "PASCALCOIN_DATA_FOLDER"
-
-  
-*************************
-** COMPILE WITH DELPHI **
-*************************
-
-(In Delphi, you can only run in Windows)
-
-- Just open Delphi 2010, open project "PascalCoinWallet.dpr" located at "SOURCE_CODE_FOLDER"
-- Go to "Project > Options" and put "Synapse\lib" folder at Search Path option  (This will enable Delphi to find Synapse source code)
-- Build + Compile
-- Exe file will be: "PascalCoinWallet.exe"
-
-*************************
-** COMPILE WITH LAZARUS **
-*************************
-
-- Just open Lazarus (tested with Lazarus 1.6 and FPC 3.0)
-- Open project "PascalCoinWalletLazarus.lpi"
-- Check that 
-- Build + Compile
-- Executable file will be: "PascalCoinWalletLazarus"
-
-*****************************
-** BUILD OPENSSL FOR LINUX **
-*****************************
-
-Build OpenSSL is only necessary in Linux. In Windows you can download a build version from https://indy.fulgan.com/SSL/
-If you want to build on Windows, search how to at Google.
-Note: Tested with OpenSSL 1.1.0b (2016-Sep-26)
-- LINUX INSTRUCTIONS
-- Download OpenSSL from www.openssl.org (Preferred version 1.1.0b)
-- Unzip files to any folder, we will call it "OpenSSLSourceFolder"
-- Open a linux terminal
-  - Go to "OpenSSLSourceFolder"
-    cd /"OpenSSLSourceFolder"
-  - Create a temporal destination folder
-    mkdir tmp_openssl
-  - Config build options with this temporal destination dir
-    ./config shared --prefix=/"OpenSSLSourceFolder"/tmp_openssl
-  - Execute make and install
-    make
-	install
-  - We will find a file called "libcrypto.so.1.1" at folder "OpenSSLSourceFolder"/tmp_openssl/lib
-  - copy "libcrypto.so.1.1" to your executable folder (where you have been compiled PascalCoinWalletLazarus = "SOURCE_CODE_FOLDER")
-  - DON'T RENAME this file, because PascalCoin executable needs a file called "libcrypto.so.1.1" when compiled in Linux with OpenSSLv1.1 option enabled
-- If you download a version 1.0, then file name of compiled OpenSSL library must be "libcrypto.so.1.0.0" and save it at "SOURCE_CODE_FOLDER"
-
-*******************
-** FAQ's section **
-*******************
-
-************
-** FAQ 01 **
-************
-
-FAQ 01 -> Lazarus does not compile with Linux (example: file "interfaces" not found or missing)
-Explanation: In a fresh Ubuntu 16.04.1 (perhaps other versions too) with Lazarus 1.6 (downloaded and fresh installed) you cannot compile PascalCoin (and nor anyone other Pascal program)
-This is because you must build Lazarus core.
-Solution:
-- Open Lazarus and close all projects
-- Go to menu "Tools" > "Configure Build Lazarus"
-- Select Profile to build "Clean Up+ Build all"
-- Click to "Build"
-  - Lazarus will build itself and reboot
-- Open Lazarus again and check if you can compile without "interfaces" file error
-  - If not, then try again to build Lazarus selecting other Profile to build options (Perhaps "Debug IDE")
-  - If not... sorry... google search ;-)
-
-************
-** FAQ 02 **
-************
-
-If Application does not start showing a "file not found libeay32.dll" or "libcrypto.so.1.1" or "libeay64.dll"...
-Solution: Read "DOWNLOAD SOURCE CODE" section
-
-
-Copyright (c) 2016 Albert Molina
-
-If you like it, consider a donation using BitCoin:
-16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk

+ 19 - 5
PascalCoinServer.dpr

@@ -5,14 +5,28 @@ program PascalCoinServer;
 uses
 uses
   SysUtils,
   SysUtils,
   SyncObjs,
   SyncObjs,
-  UAES in 'Units\Utils\UAES.pas',
-  UJSONFunctions in 'Units\Utils\UJSONFunctions.pas',
+  UAES in 'Units\PascalCoin\UAES.pas',
   UCrypto in 'Units\PascalCoin\UCrypto.pas',
   UCrypto in 'Units\PascalCoin\UCrypto.pas',
-  UAccounts in 'Units\PascalCoin\UAccounts.pas',
   UConst in 'Units\PascalCoin\UConst.pas',
   UConst in 'Units\PascalCoin\UConst.pas',
-  UThread in 'Units\PascalCoin\UThread.pas',
   ULog in 'Units\PascalCoin\ULog.pas',
   ULog in 'Units\PascalCoin\ULog.pas',
-  UServerApp in 'Units\PascalCoin\UServerApp.pas';
+  UServerApp in 'Units\PascalCoin\UServerApp.pas',
+  UAccounts in 'Units\PascalCoin\UAccounts.pas',
+  UBlockChain in 'Units\PascalCoin\UBlockChain.pas',
+  UECIES in 'Units\PascalCoin\UECIES.pas',
+  UFileStorage in 'Units\PascalCoin\UFileStorage.pas',
+  UNetProtocol in 'Units\PascalCoin\UNetProtocol.pas',
+  UNode in 'Units\PascalCoin\UNode.pas',
+  UOpenSSL in 'Units\PascalCoin\UOpenSSL.pas',
+  UOpenSSLdef in 'Units\PascalCoin\UOpenSSLdef.pas',
+  UOpTransaction in 'Units\PascalCoin\UOpTransaction.pas',
+  URPC in 'Units\PascalCoin\URPC.pas',
+  UTCPIP in 'Units\PascalCoin\UTCPIP.pas',
+  UThread in 'Units\PascalCoin\UThread.pas',
+  UTime in 'Units\PascalCoin\UTime.pas',
+  UWalletKeys in 'Units\PascalCoin\UWalletKeys.pas',
+  UMiner in 'Units\PascalCoin\UMiner.pas',
+  UFolderHelper in 'Units\Utils\UFolderHelper.pas',
+  UJSONFunctions in 'Units\Utils\UJSONFunctions.pas';
 
 
 type
 type
   TOutputLogger = class
   TOutputLogger = class

BIN
PascalCoinWallet.res


+ 0 - 1
PascalCoinWalletLazarus.lpi

@@ -14,7 +14,6 @@
       <Title Value="PascalCoinWalletLazarus"/>
       <Title Value="PascalCoinWalletLazarus"/>
       <UseAppBundle Value="False"/>
       <UseAppBundle Value="False"/>
       <ResourceType Value="res"/>
       <ResourceType Value="res"/>
-      <Icon Value="0"/>
     </General>
     </General>
     <i18n>
     <i18n>
       <EnableI18N LFM="False"/>
       <EnableI18N LFM="False"/>

BIN
PascalCoinWalletLazarus.res


+ 58 - 53
README.md

@@ -1,80 +1,83 @@
-Pascal Coin: P2P Cryptocurrency without need of historical operations.
-
-Copyright (c) 2016 Albert Molina
-
-THIS IS EXPERIMENTAL SOFTWARE. Use it for educational purposes only.
-
-This software is a Node of the Pascal Coin P2P Cryptocurrency.
-It can be used to Mine and Explore blocks and operations.
-
-Distributed under the MIT software license, see the accompanying file 
-LICENSE  or visit http://www.opensource.org/licenses/mit-license.php.
-
-This product includes software developed by the OpenSSL Project and Denis
-Grinyuk (https://github.com/Arvur/OpenSSL-Delphi), and some
-cryptographic functions inspirated in code written by Ladar Levison and 
-Marco Ferrante.
-Original source code is written in Pascal Language and is available at 
-https://github.com/PascalCoin/PascalCoin
-
-
-HOW TO COMPILE:
-
-Version 1.0.9 of Pascal Coin Wallet can be compiled with Delphi and Lazarus and run in Windows or Linux
+# Pascal Coin: P2P Cryptocurrency without need of historical operations.  
+  
+Copyright (c) 2016 Albert Molina  
+  
+THIS IS EXPERIMENTAL SOFTWARE. Use it for educational purposes only.  
+  
+This software is a Node of the Pascal Coin P2P Cryptocurrency.  
+It can be used to Mine and Explore blocks and operations.  
+  
+Distributed under the MIT software license, see the accompanying file  
+LICENSE  or visit http://www.opensource.org/licenses/mit-license.php.  
+
+This product includes software developed by the OpenSSL Project and Denis  
+Grinyuk (https://github.com/Arvur/OpenSSL-Delphi), and some  
+cryptographic functions inspirated in code written by Ladar Levison and   
+Marco Ferrante.  
+Original source code is written in Pascal Language and is available at   
+https://github.com/PascalCoin/PascalCoin  
+  
+  
+## HOW TO COMPILE:  
+  
+See instructions at GitHub Wiki: https://github.com/PascalCoin/PascalCoin/wiki
+  
+  
+Enjoy Pascal Coin!
+  
+## Donations  
+  
+If you like it, consider a donation using BitCoin:
+16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
 
 
-- Included source code available at https://github.com/PascalCoin/PascalCoin
-- Read "COMPILE_INSTRUCTIONS" file with instructions
+Also, consider a donation at PascalCoin development account: "0-10"
 
 
-To run:
-- Windows: libeay32.dll - Can be downloaded from https://indy.fulgan.com/SSL/
-- Linux: libcrypto.so.1.0.0 or libcrypto.so.1.1 (Instructions in "COMPILE_INSTRUCTIONS" file)
+## History:  
 
 
+### Build 1.1.0.0 - 2016-11-03
 
 
-Enjoy Pascal Coin!
+- JSON-RPC Server included
+- Minor changes
 
 
-If you like it, consider a donation using BitCoin:
-16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
 
 
-History:
+### Build 1.0.9.0 - 2016-10-21
 
 
-Build 1.0.9.0 - 2016-10-21
---------------------------
 - Corrected a BUG (BUG-101) that causes blocking connections when received more than 100 connections, causing "alone in the world" after a cert period time.
 - Corrected a BUG (BUG-101) that causes blocking connections when received more than 100 connections, causing "alone in the world" after a cert period time.
 - It's necessary to update because new version will refuse old versions to make network stable.
 - It's necessary to update because new version will refuse old versions to make network stable.
 
 
 
 
-Build 1.0.8.0 - 2016-10-20
---------------------------
+### Build 1.0.8.0 - 2016-10-20
+
 - Cross compatible
 - Cross compatible
 - Can compile with Delphi or Lazarus (Free Pascal)
 - Can compile with Delphi or Lazarus (Free Pascal)
 - New storage system. No more access database
 - New storage system. No more access database
 - Network hashrate calculation
 - Network hashrate calculation
 
 
 
 
-Build 1.0.7.0 - 2016-10-10
---------------------------
+### Build 1.0.7.0 - 2016-10-10
+
 - Introducing basic JSON-RPC to allow GPU miners development (Third party).
 - Introducing basic JSON-RPC to allow GPU miners development (Third party).
 - See file "HOWTO_DEVELOP_GPU_MINER_FOR_PASCALCOIN.txt"
 - See file "HOWTO_DEVELOP_GPU_MINER_FOR_PASCALCOIN.txt"
 - No more CPU mining due exists GPU mining
 - No more CPU mining due exists GPU mining
 
 
 
 
-Build 1.0.6.0 - 2016-10-04
---------------------------
+### Build 1.0.6.0 - 2016-10-04
+
 - Memory leaks corrections
 - Memory leaks corrections
 - Introducing net protocol 2-3
 - Introducing net protocol 2-3
 - Source code modified, next build will be compiled with Lazarus and FPC
 - Source code modified, next build will be compiled with Lazarus and FPC
 
 
 
 
-Build 1.0.5.0 - 2016-09-21
---------------------------
+### Build 1.0.5.0 - 2016-09-21
+
 - Massive operations, selecting multiple accounts
 - Massive operations, selecting multiple accounts
 - Filter accounts by balance
 - Filter accounts by balance
 - Correct operations explorer order of operations for each block (descending order)
 - Correct operations explorer order of operations for each block (descending order)
 - Minor changes
 - Minor changes
 
 
 
 
-Build 1.0.4.0 - 2016-09-16
---------------------------
+### Build 1.0.4.0 - 2016-09-16
+
 - IMPORTANT: Introducing net protocol changes: Must update!
 - IMPORTANT: Introducing net protocol changes: Must update!
 - More and more and more stable
 - More and more and more stable
 - Prevents "Alone in the world" if everybody is updated ;-)
 - Prevents "Alone in the world" if everybody is updated ;-)
@@ -82,8 +85,8 @@ Build 1.0.4.0 - 2016-09-16
 - IP nodes configurator
 - IP nodes configurator
 
 
 
 
-Build 1.0.3.0 - 2016-09-08
---------------------------
+### Build 1.0.3.0 - 2016-09-08
+
 - Important changes to database 
 - Important changes to database 
 - Peer cache
 - Peer cache
 - Issues with Connections
 - Issues with Connections
@@ -92,8 +95,8 @@ Build 1.0.3.0 - 2016-09-08
 - Invalid local time detector
 - Invalid local time detector
 
 
 
 
-Build 1.0.2.0 - 2016-08-31
---------------------------
+### Build 1.0.2.0 - 2016-08-31
+
 - Improved hashing speed
 - Improved hashing speed
 - Allow mining without opening external ports
 - Allow mining without opening external ports
 - Choose how many CPU's want to mine
 - Choose how many CPU's want to mine
@@ -101,12 +104,14 @@ Build 1.0.2.0 - 2016-08-31
 - More stable
 - More stable
 - Some miner modifications
 - Some miner modifications
 
 
-Build 1.0.1.0 - 2016-08-12
---------------------------
+### Build 1.0.1.0 - 2016-08-12
+
 - Included an option to Import/Export Wallet keys file
 - Included an option to Import/Export Wallet keys file
 - Some miner modifications
 - Some miner modifications
 
 
 
 
-Build 1.0.0.0 - 2016-08-11
---------------------------
-- First stable version.
+### Build 1.0.0.0 - 2016-08-11
+
+- First stable version.
+- Created with Genesis block hardcoded
+- Published at same time than Genesis block. NO PREMINE

+ 58 - 53
README.txt

@@ -1,80 +1,83 @@
-Pascal Coin: P2P Cryptocurrency without need of historical operations.
-
-Copyright (c) 2016 Albert Molina
-
-THIS IS EXPERIMENTAL SOFTWARE. Use it for educational purposes only.
-
-This software is a Node of the Pascal Coin P2P Cryptocurrency.
-It can be used to Mine and Explore blocks and operations.
-
-Distributed under the MIT software license, see the accompanying file 
-LICENSE  or visit http://www.opensource.org/licenses/mit-license.php.
-
-This product includes software developed by the OpenSSL Project and Denis
-Grinyuk (https://github.com/Arvur/OpenSSL-Delphi), and some
-cryptographic functions inspirated in code written by Ladar Levison and 
-Marco Ferrante.
-Original source code is written in Pascal Language and is available at 
-https://github.com/PascalCoin/PascalCoin
-
-
-HOW TO COMPILE:
-
-Version 1.0.9 of Pascal Coin Wallet can be compiled with Delphi and Lazarus and run in Windows or Linux
+# Pascal Coin: P2P Cryptocurrency without need of historical operations.  
+  
+Copyright (c) 2016 Albert Molina  
+  
+THIS IS EXPERIMENTAL SOFTWARE. Use it for educational purposes only.  
+  
+This software is a Node of the Pascal Coin P2P Cryptocurrency.  
+It can be used to Mine and Explore blocks and operations.  
+  
+Distributed under the MIT software license, see the accompanying file  
+LICENSE  or visit http://www.opensource.org/licenses/mit-license.php.  
+
+This product includes software developed by the OpenSSL Project and Denis  
+Grinyuk (https://github.com/Arvur/OpenSSL-Delphi), and some  
+cryptographic functions inspirated in code written by Ladar Levison and   
+Marco Ferrante.  
+Original source code is written in Pascal Language and is available at   
+https://github.com/PascalCoin/PascalCoin  
+  
+  
+## HOW TO COMPILE:  
+  
+See instructions at GitHub Wiki: https://github.com/PascalCoin/PascalCoin/wiki
+  
+  
+Enjoy Pascal Coin!
+  
+## Donations  
+  
+If you like it, consider a donation using BitCoin:
+16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
 
 
-- Included source code available at https://github.com/PascalCoin/PascalCoin
-- Read "COMPILE_INSTRUCTIONS" file with instructions
+Also, consider a donation at PascalCoin development account: "0-10"
 
 
-To run:
-- Windows: libeay32.dll - Can be downloaded from https://indy.fulgan.com/SSL/
-- Linux: libcrypto.so.1.0.0 or libcrypto.so.1.1 (Instructions in "COMPILE_INSTRUCTIONS" file)
+## History:  
 
 
+### Build 1.1.0.0 - 2016-11-03
 
 
-Enjoy Pascal Coin!
+- JSON-RPC Server included
+- Minor changes
 
 
-If you like it, consider a donation using BitCoin:
-16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
 
 
-History:
+### Build 1.0.9.0 - 2016-10-21
 
 
-Build 1.0.9.0 - 2016-10-21
---------------------------
 - Corrected a BUG (BUG-101) that causes blocking connections when received more than 100 connections, causing "alone in the world" after a cert period time.
 - Corrected a BUG (BUG-101) that causes blocking connections when received more than 100 connections, causing "alone in the world" after a cert period time.
 - It's necessary to update because new version will refuse old versions to make network stable.
 - It's necessary to update because new version will refuse old versions to make network stable.
 
 
 
 
-Build 1.0.8.0 - 2016-10-20
---------------------------
+### Build 1.0.8.0 - 2016-10-20
+
 - Cross compatible
 - Cross compatible
 - Can compile with Delphi or Lazarus (Free Pascal)
 - Can compile with Delphi or Lazarus (Free Pascal)
 - New storage system. No more access database
 - New storage system. No more access database
 - Network hashrate calculation
 - Network hashrate calculation
 
 
 
 
-Build 1.0.7.0 - 2016-10-10
---------------------------
+### Build 1.0.7.0 - 2016-10-10
+
 - Introducing basic JSON-RPC to allow GPU miners development (Third party).
 - Introducing basic JSON-RPC to allow GPU miners development (Third party).
 - See file "HOWTO_DEVELOP_GPU_MINER_FOR_PASCALCOIN.txt"
 - See file "HOWTO_DEVELOP_GPU_MINER_FOR_PASCALCOIN.txt"
 - No more CPU mining due exists GPU mining
 - No more CPU mining due exists GPU mining
 
 
 
 
-Build 1.0.6.0 - 2016-10-04
---------------------------
+### Build 1.0.6.0 - 2016-10-04
+
 - Memory leaks corrections
 - Memory leaks corrections
 - Introducing net protocol 2-3
 - Introducing net protocol 2-3
 - Source code modified, next build will be compiled with Lazarus and FPC
 - Source code modified, next build will be compiled with Lazarus and FPC
 
 
 
 
-Build 1.0.5.0 - 2016-09-21
---------------------------
+### Build 1.0.5.0 - 2016-09-21
+
 - Massive operations, selecting multiple accounts
 - Massive operations, selecting multiple accounts
 - Filter accounts by balance
 - Filter accounts by balance
 - Correct operations explorer order of operations for each block (descending order)
 - Correct operations explorer order of operations for each block (descending order)
 - Minor changes
 - Minor changes
 
 
 
 
-Build 1.0.4.0 - 2016-09-16
---------------------------
+### Build 1.0.4.0 - 2016-09-16
+
 - IMPORTANT: Introducing net protocol changes: Must update!
 - IMPORTANT: Introducing net protocol changes: Must update!
 - More and more and more stable
 - More and more and more stable
 - Prevents "Alone in the world" if everybody is updated ;-)
 - Prevents "Alone in the world" if everybody is updated ;-)
@@ -82,8 +85,8 @@ Build 1.0.4.0 - 2016-09-16
 - IP nodes configurator
 - IP nodes configurator
 
 
 
 
-Build 1.0.3.0 - 2016-09-08
---------------------------
+### Build 1.0.3.0 - 2016-09-08
+
 - Important changes to database 
 - Important changes to database 
 - Peer cache
 - Peer cache
 - Issues with Connections
 - Issues with Connections
@@ -92,8 +95,8 @@ Build 1.0.3.0 - 2016-09-08
 - Invalid local time detector
 - Invalid local time detector
 
 
 
 
-Build 1.0.2.0 - 2016-08-31
---------------------------
+### Build 1.0.2.0 - 2016-08-31
+
 - Improved hashing speed
 - Improved hashing speed
 - Allow mining without opening external ports
 - Allow mining without opening external ports
 - Choose how many CPU's want to mine
 - Choose how many CPU's want to mine
@@ -101,12 +104,14 @@ Build 1.0.2.0 - 2016-08-31
 - More stable
 - More stable
 - Some miner modifications
 - Some miner modifications
 
 
-Build 1.0.1.0 - 2016-08-12
---------------------------
+### Build 1.0.1.0 - 2016-08-12
+
 - Included an option to Import/Export Wallet keys file
 - Included an option to Import/Export Wallet keys file
 - Some miner modifications
 - Some miner modifications
 
 
 
 
-Build 1.0.0.0 - 2016-08-11
---------------------------
-- First stable version.
+### Build 1.0.0.0 - 2016-08-11
+
+- First stable version.
+- Created with Genesis block hardcoded
+- Published at same time than Genesis block. NO PREMINE

+ 17 - 11
Units/Forms/UFRMAbout.lfm

@@ -151,7 +151,7 @@ object FRMAbout: TFRMAbout
     Left = 90
     Left = 90
     Height = 25
     Height = 25
     Top = 15
     Top = 15
-    Width = 425
+    Width = 382
     Caption = 'Pascal Coin Wallet, Miner && Explorer'
     Caption = 'Pascal Coin Wallet, Miner && Explorer'
     Font.Color = clBlack
     Font.Color = clBlack
     Font.Height = -21
     Font.Height = -21
@@ -164,7 +164,7 @@ object FRMAbout: TFRMAbout
     Left = 15
     Left = 15
     Height = 13
     Height = 13
     Top = 356
     Top = 356
-    Width = 36
+    Width = 30
     Caption = 'Build:'
     Caption = 'Build:'
     Font.Color = clWindowText
     Font.Color = clWindowText
     Font.Height = -11
     Font.Height = -11
@@ -177,7 +177,7 @@ object FRMAbout: TFRMAbout
     Left = 15
     Left = 15
     Height = 13
     Height = 13
     Top = 375
     Top = 375
-    Width = 57
+    Width = 50
     Caption = 'Protocol:'
     Caption = 'Protocol:'
     Font.Color = clWindowText
     Font.Color = clWindowText
     Font.Height = -11
     Font.Height = -11
@@ -190,7 +190,7 @@ object FRMAbout: TFRMAbout
     Left = 90
     Left = 90
     Height = 13
     Height = 13
     Top = 320
     Top = 320
-    Width = 76
+    Width = 65
     Caption = 'Source Code:'
     Caption = 'Source Code:'
     ParentColor = False
     ParentColor = False
   end
   end
@@ -198,7 +198,7 @@ object FRMAbout: TFRMAbout
     Left = 90
     Left = 90
     Height = 13
     Height = 13
     Top = 339
     Top = 339
-    Width = 154
+    Width = 135
     Caption = 'Check For New Versions:'
     Caption = 'Check For New Versions:'
     Font.Color = clWindowText
     Font.Color = clWindowText
     Font.Height = -11
     Font.Height = -11
@@ -212,7 +212,7 @@ object FRMAbout: TFRMAbout
     Left = 170
     Left = 170
     Height = 13
     Height = 13
     Top = 320
     Top = 320
-    Width = 260
+    Width = 240
     Caption = 'https://github.com/PascalCoin/PascalCoin'
     Caption = 'https://github.com/PascalCoin/PascalCoin'
     Font.Color = clBlue
     Font.Color = clBlue
     Font.Height = -11
     Font.Height = -11
@@ -227,7 +227,7 @@ object FRMAbout: TFRMAbout
     Left = 237
     Left = 237
     Height = 13
     Height = 13
     Top = 339
     Top = 339
-    Width = 270
+    Width = 253
     Caption = 'https://sourceforge.net/projects/pascalcoin'
     Caption = 'https://sourceforge.net/projects/pascalcoin'
     Font.Color = clBlue
     Font.Color = clBlue
     Font.Height = -11
     Font.Height = -11
@@ -246,14 +246,20 @@ object FRMAbout: TFRMAbout
     Lines.Strings = (
     Lines.Strings = (
       'Copyright (c) 2016 Albert Molina'
       'Copyright (c) 2016 Albert Molina'
       ''
       ''
-      'This software is a Node of the Pascal Coin P2P Cryptocurrency. A Crypto currency without need of historical operations. It can be used to Mine and Explore blocks and operations.'
+      'This software is a Node of the Pascal Coin P2P Cryptocurrency. A Crypto currency without '
+      'need of historical operations. It can be used to Mine and Explore blocks and operations.'
       ''
       ''
-      'Distributed under the MIT software license, see the accompanying file LICENSE  or visit http://www.opensource.org/licenses/mit-license.php.'
+      'Distributed under the MIT software license, see the accompanying file LICENSE  or visit '
+      'http://www.opensource.org/licenses/mit-license.php.'
       ''
       ''
       'THIS IS EXPERIMENTAL SOFTWARE. Use it for educational purposes only.'
       'THIS IS EXPERIMENTAL SOFTWARE. Use it for educational purposes only.'
       ''
       ''
-      'This product includes software developed by the OpenSSL Project and Denis Grinyuk (https://github.com/Arvur/OpenSSL-Delphi), some cryptographic functions inspirated in code written by Ladar Levison and Marco Ferrante, and Synapse Socket code copyright of Lukas Gebauer.'
-      'Original source code is written in Pascal Language and is available at https://github.com/PascalCoin/PascalCoin'
+      'This product includes software developed by the OpenSSL Project and Denis Grinyuk '
+      '(https://github.com/Arvur/OpenSSL-Delphi), some cryptographic functions inspirated in code '
+      'written by Ladar Levison and Marco Ferrante, and Synapse Socket code copyright of Lukas '
+      'Gebauer.'
+      'Original source code is written in Pascal Language and is available at '
+      'https://github.com/PascalCoin/PascalCoin'
       ''
       ''
       'If you like it, consider a donation using BitCoin:'
       'If you like it, consider a donation using BitCoin:'
       '16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk'
       '16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk'

+ 37 - 1
Units/Forms/UFRMWallet.dfm

@@ -374,6 +374,10 @@ object FRMWallet: TFRMWallet
     OnChange = PageControlChange
     OnChange = PageControlChange
     object tsMyAccounts: TTabSheet
     object tsMyAccounts: TTabSheet
       Caption = 'Accounts Explorer'
       Caption = 'Accounts Explorer'
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object Splitter1: TSplitter
       object Splitter1: TSplitter
         Left = 380
         Left = 380
         Top = 66
         Top = 66
@@ -579,6 +583,10 @@ object FRMWallet: TFRMWallet
         TabOrder = 2
         TabOrder = 2
         object tsAccountOperations: TTabSheet
         object tsAccountOperations: TTabSheet
           Caption = 'Operations of selected Account'
           Caption = 'Operations of selected Account'
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object dgAccountOperations: TDrawGrid
           object dgAccountOperations: TDrawGrid
             Left = 0
             Left = 0
             Top = 0
             Top = 0
@@ -598,6 +606,10 @@ object FRMWallet: TFRMWallet
         object tsMultiSelectAccounts: TTabSheet
         object tsMultiSelectAccounts: TTabSheet
           Caption = 'Selected accounts for massive operations'
           Caption = 'Selected accounts for massive operations'
           ImageIndex = 1
           ImageIndex = 1
+          ExplicitLeft = 0
+          ExplicitTop = 0
+          ExplicitWidth = 0
+          ExplicitHeight = 0
           object dgSelectedAccounts: TDrawGrid
           object dgSelectedAccounts: TDrawGrid
             Left = 41
             Left = 41
             Top = 31
             Top = 31
@@ -787,6 +799,10 @@ object FRMWallet: TFRMWallet
     object tsPendingOperations: TTabSheet
     object tsPendingOperations: TTabSheet
       Caption = 'Pending Operations'
       Caption = 'Pending Operations'
       ImageIndex = 5
       ImageIndex = 5
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object dgPendingOperations: TDrawGrid
       object dgPendingOperations: TDrawGrid
         Left = 0
         Left = 0
         Top = 86
         Top = 86
@@ -834,6 +850,10 @@ object FRMWallet: TFRMWallet
     object tsBlockChain: TTabSheet
     object tsBlockChain: TTabSheet
       Caption = 'BlockChain Explorer'
       Caption = 'BlockChain Explorer'
       ImageIndex = 1
       ImageIndex = 1
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object Panel2: TPanel
       object Panel2: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -879,6 +899,10 @@ object FRMWallet: TFRMWallet
     object tsOperations: TTabSheet
     object tsOperations: TTabSheet
       Caption = 'Operations Explorer'
       Caption = 'Operations Explorer'
       ImageIndex = 1
       ImageIndex = 1
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object Panel1: TPanel
       object Panel1: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -924,6 +948,10 @@ object FRMWallet: TFRMWallet
     object tsLogs: TTabSheet
     object tsLogs: TTabSheet
       Caption = 'Logs'
       Caption = 'Logs'
       ImageIndex = 2
       ImageIndex = 2
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       object pnlTopLogs: TPanel
       object pnlTopLogs: TPanel
         Left = 0
         Left = 0
         Top = 0
         Top = 0
@@ -953,6 +981,10 @@ object FRMWallet: TFRMWallet
     object tsNodeStats: TTabSheet
     object tsNodeStats: TTabSheet
       Caption = 'Node Stats'
       Caption = 'Node Stats'
       ImageIndex = 3
       ImageIndex = 3
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       DesignSize = (
       DesignSize = (
         841
         841
         404)
         404)
@@ -1015,6 +1047,10 @@ object FRMWallet: TFRMWallet
     object tsMessages: TTabSheet
     object tsMessages: TTabSheet
       Caption = 'Messages'
       Caption = 'Messages'
       ImageIndex = 6
       ImageIndex = 6
+      ExplicitLeft = 0
+      ExplicitTop = 0
+      ExplicitWidth = 0
+      ExplicitHeight = 0
       DesignSize = (
       DesignSize = (
         841
         841
         404)
         404)
@@ -1243,7 +1279,7 @@ object FRMWallet: TFRMWallet
     Left = 105
     Left = 105
     Top = 180
     Top = 180
     Bitmap = {
     Bitmap = {
-      494C010102000800640110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      494C0101020008007C0110003000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000003600000028000000400000003000000001002000000000000030
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000
       0000000000000000002A292929D60B0B0BF4111111EE0000006B000000000000

+ 26 - 10
Units/Forms/UFRMWallet.pas

@@ -29,7 +29,7 @@ uses
   Dialogs, ExtCtrls, ComCtrls, UWalletKeys, StdCtrls,
   Dialogs, ExtCtrls, ComCtrls, UWalletKeys, StdCtrls,
   ULog, DB, Grids, DBGrids, UAppParams,
   ULog, DB, Grids, DBGrids, UAppParams,
   UBlockChain, UNode, DBCtrls, UGridUtils, UMiner, UAccounts, Menus, ImgList,
   UBlockChain, UNode, DBCtrls, UGridUtils, UMiner, UAccounts, Menus, ImgList,
-  UNetProtocol, UCrypto, Buttons, UPoolMining;
+  UNetProtocol, UCrypto, Buttons, UPoolMining, URPC;
 
 
 type
 type
   TMinerPrivateKey = (mpk_NewEachTime, mpk_Random, mpk_Selected);
   TMinerPrivateKey = (mpk_NewEachTime, mpk_Random, mpk_Selected);
@@ -213,7 +213,7 @@ type
     { Private declarations }
     { Private declarations }
     FNode : TNode;
     FNode : TNode;
     FIsActivated : Boolean;
     FIsActivated : Boolean;
-    FWalletKeys : TWalletKeys;
+    FWalletKeys : TWalletKeysExt;
     FLog : TLog;
     FLog : TLog;
     FAppParams : TAppParams;
     FAppParams : TAppParams;
     FNodeNotifyEvents : TNodeNotifyEvents;
     FNodeNotifyEvents : TNodeNotifyEvents;
@@ -230,6 +230,7 @@ type
     FMinAccountBalance : Int64;
     FMinAccountBalance : Int64;
     FMaxAccountBalance : Int64;
     FMaxAccountBalance : Int64;
     FPoolMiningServer : TPoolMiningServer;
     FPoolMiningServer : TPoolMiningServer;
+    FRPCServer : TRPCServer;
     //Procedure CheckMining;
     //Procedure CheckMining;
     Procedure OnNewAccount(Sender : TObject);
     Procedure OnNewAccount(Sender : TObject);
     Procedure OnReceivedHelloMessage(Sender : TObject);
     Procedure OnReceivedHelloMessage(Sender : TObject);
@@ -259,7 +260,7 @@ type
     Function DoUpdateAccountsFilter : Boolean;
     Function DoUpdateAccountsFilter : Boolean;
   public
   public
     { Public declarations }
     { Public declarations }
-    Property WalletKeys : TWalletKeys read FWalletKeys;
+    Property WalletKeys : TWalletKeysExt read FWalletKeys;
     Property MinersBlocksFound : Integer read FMinersBlocksFound write SetMinersBlocksFound;
     Property MinersBlocksFound : Integer read FMinersBlocksFound write SetMinersBlocksFound;
   end;
   end;
 
 
@@ -326,6 +327,11 @@ begin
     FNode := TNode.Node;
     FNode := TNode.Node;
     FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
     FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
     FNode.PeerCache := FAppParams.ParamByName[CT_PARAM_PeerCache].GetAsString('')+';'+CT_Discover_IPs;
     FNode.PeerCache := FAppParams.ParamByName[CT_PARAM_PeerCache].GetAsString('')+';'+CT_Discover_IPs;
+    // Create RPC server
+    FRPCServer := TRPCServer.Create;
+    FRPCServer.WalletKeys := WalletKeys;
+    FRPCServer.Active := true;
+    WalletKeys.SafeBox := FNode.Bank.SafeBox;
     // Check Database
     // Check Database
     FNode.Bank.StorageClass := TFileStorage;
     FNode.Bank.StorageClass := TFileStorage;
     TFileStorage(FNode.Bank.Storage).DatabaseFolder := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'Data';
     TFileStorage(FNode.Bank.Storage).DatabaseFolder := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'Data';
@@ -706,6 +712,7 @@ end;
 procedure TFRMWallet.FormCreate(Sender: TObject);
 procedure TFRMWallet.FormCreate(Sender: TObject);
 Var i : Integer;
 Var i : Integer;
 begin
 begin
+  FRPCServer := Nil;
   FMinAccountBalance := 0;
   FMinAccountBalance := 0;
   FMaxAccountBalance := CT_MaxWalletAmount;
   FMaxAccountBalance := CT_MaxWalletAmount;
   FMessagesUnreadCount := 0;
   FMessagesUnreadCount := 0;
@@ -720,7 +727,7 @@ begin
   FOrderedAccountsKeyList := Nil;
   FOrderedAccountsKeyList := Nil;
   TimerUpdateStatus.Enabled := false;
   TimerUpdateStatus.Enabled := false;
   FIsActivated := false;
   FIsActivated := false;
-  FWalletKeys := TWalletKeys.Create(Self);
+  FWalletKeys := TWalletKeysExt.Create(Self);
   for i := 0 to StatusBar.Panels.Count - 1 do begin
   for i := 0 to StatusBar.Panels.Count - 1 do begin
     StatusBar.Panels[i].Text := '';
     StatusBar.Panels[i].Text := '';
   end;
   end;
@@ -779,6 +786,7 @@ Var i : Integer;
 begin
 begin
   TLog.NewLog(ltinfo,Classname,'Destroying form - START');
   TLog.NewLog(ltinfo,Classname,'Destroying form - START');
   Try
   Try
+  FreeAndNil(FRPCServer);
   FreeAndNil(FPoolMiningServer);
   FreeAndNil(FPoolMiningServer);
   step := 'Saving params';
   step := 'Saving params';
   SaveAppParams;
   SaveAppParams;
@@ -1201,9 +1209,16 @@ begin
         if P.last_connection>0 then begin
         if P.last_connection>0 then begin
           s := s + ' Last connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection)));
           s := s + ' Last connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection)));
         end;
         end;
+        if P.last_connection_by_server>0 then begin
+          s := s + ' Last server connection: '+DateTimeToStr(UnivDateTime2LocalDateTime( UnixToUnivDateTime(P^.last_connection_by_server)));
+        end;
         if (P.last_attempt_to_connect>0) then begin
         if (P.last_attempt_to_connect>0) then begin
-          s := s + ' Last attempt to connect: '+DateTimeToStr(P^.last_attempt_to_connect)+' (Attempts: '+inttostr(P^.total_failed_attemps_to_connect)+')';
+          s := s + ' Last attempt to connect: '+DateTimeToStr(P^.last_attempt_to_connect);
+        end;
+        if (P.total_failed_attemps_to_connect>0) then begin
+          s := s + ' (Attempts: '+inttostr(P^.total_failed_attemps_to_connect)+')';
         end;
         end;
+
         strings.Add(s);
         strings.Add(s);
       end;
       end;
     Finally
     Finally
@@ -1455,7 +1470,7 @@ end;
 
 
 procedure TFRMWallet.UpdateAccounts(RefreshData : Boolean);
 procedure TFRMWallet.UpdateAccounts(RefreshData : Boolean);
 Var accl : TOrderedCardinalList;
 Var accl : TOrderedCardinalList;
-  l : TList;
+  l : TOrderedCardinalList;
   i,j,k : Integer;
   i,j,k : Integer;
   c  : Cardinal;
   c  : Cardinal;
   applyfilter : Boolean;
   applyfilter : Boolean;
@@ -1482,9 +1497,9 @@ begin
               l := FOrderedAccountsKeyList.AccountKeyList[j];
               l := FOrderedAccountsKeyList.AccountKeyList[j];
               for k := 0 to l.Count - 1 do begin
               for k := 0 to l.Count - 1 do begin
                 if applyfilter then begin
                 if applyfilter then begin
-                  acc := FNode.Bank.SafeBox.Account(Cardinal(l[k]));
+                  acc := FNode.Bank.SafeBox.Account(l.Get(k));
                   if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
                   if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
-                end else accl.Add(Cardinal(l[k]));
+                end else accl.Add(l.Get(k));
               end;
               end;
             end;
             end;
           end;
           end;
@@ -1496,9 +1511,9 @@ begin
               l := FOrderedAccountsKeyList.AccountKeyList[j];
               l := FOrderedAccountsKeyList.AccountKeyList[j];
               for k := 0 to l.Count - 1 do begin
               for k := 0 to l.Count - 1 do begin
                 if applyfilter then begin
                 if applyfilter then begin
-                  acc := FNode.Bank.SafeBox.Account(Cardinal(l[k]));
+                  acc := FNode.Bank.SafeBox.Account(l.Get(k));
                   if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
                   if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
-                end else accl.Add(Cardinal(l[k]));
+                end else accl.Add(l.Get(k));
               end;
               end;
             end;
             end;
           end;
           end;
@@ -1638,6 +1653,7 @@ begin
     FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
     FNode.NetServer.Port := FAppParams.ParamByName[CT_PARAM_InternetServerPort].GetAsInteger(CT_NetServer_Port);
     FNode.NetServer.Active := wa;
     FNode.NetServer.Active := wa;
     FNode.Operations.BlockPayload := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
     FNode.Operations.BlockPayload := FAppParams.ParamByName[CT_PARAM_MinerName].GetAsString('');
+    FNode.NodeLogFilename := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'blocks.log';
   end;
   end;
   if Assigned(FPoolMiningServer) then begin
   if Assigned(FPoolMiningServer) then begin
     if FPoolMiningServer.Port<>FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port) then begin
     if FPoolMiningServer.Port<>FAppParams.ParamByName[CT_PARAM_JSONRPCMinerServerPort].GetAsInteger(CT_JSONRPCMinerServer_Port) then begin

+ 1 - 1
Units/PascalCoin/UAES.pas

@@ -52,7 +52,7 @@ uses
 {$IFnDEF FPC}
 {$IFnDEF FPC}
   Windows,
   Windows,
 {$ELSE}
 {$ELSE}
-  LCLIntf, LCLType, LMessages,
+  {LCLIntf, LCLType, LMessages,}
 {$ENDIF}
 {$ENDIF}
   UOpenSSL, UOpenSSLdef;
   UOpenSSL, UOpenSSLdef;
 
 

+ 49 - 50
Units/PascalCoin/UAccounts.pas

@@ -75,6 +75,28 @@ Type
     4 + (5 * 220) + 4 + 32 = 1140 max aprox
     4 + (5 * 220) + 4 + 32 = 1140 max aprox
   }
   }
 
 
+  TOrderedCardinalList = Class
+  private
+    FOrderedList : TList;
+    FDisabledsCount : Integer;
+    FModifiedWhileDisabled : Boolean;
+    FOnListChanged: TNotifyEvent;
+    Procedure NotifyChanged;
+  public
+    Constructor Create;
+    Destructor Destroy; override;
+    Function Add(Value : Cardinal) : Integer;
+    Procedure Remove(Value : Cardinal);
+    Procedure Clear;
+    Function Get(index : Integer) : Cardinal;
+    Function Count : Integer;
+    Function Find(const Value: Cardinal; var Index: Integer): Boolean;
+    Procedure Disable;
+    Procedure Enable;
+    Property OnListChanged : TNotifyEvent read FOnListChanged write FOnListChanged;
+    Procedure CopyFrom(Sender : TOrderedCardinalList);
+  End;
+
   TPCSafeBox = Class;
   TPCSafeBox = Class;
 
 
   // This is a class to quickly find accountkeys and their respective account number/s
   // This is a class to quickly find accountkeys and their respective account number/s
@@ -84,10 +106,10 @@ Type
     FAccountList : TPCSafeBox;
     FAccountList : TPCSafeBox;
     FOrderedAccountKeysList : TList; // An ordered list of pointers to quickly find account keys in account list
     FOrderedAccountKeysList : TList; // An ordered list of pointers to quickly find account keys in account list
     Function Find(Const AccountKey: TAccountKey; var Index: Integer): Boolean;
     Function Find(Const AccountKey: TAccountKey; var Index: Integer): Boolean;
-    function GetAccountKeyList(index: Integer): TList;
+    function GetAccountKeyList(index: Integer): TOrderedCardinalList;
     function GetAccountKey(index: Integer): TAccountKey;
     function GetAccountKey(index: Integer): TAccountKey;
   protected
   protected
-    Procedure Clear(RemoveAccountList : Boolean);
+    Procedure ClearAccounts(RemoveAccountList : Boolean);
   public
   public
     Constructor Create(AccountList : TPCSafeBox; AutoAddAll : Boolean);
     Constructor Create(AccountList : TPCSafeBox; AutoAddAll : Boolean);
     Destructor Destroy; override;
     Destructor Destroy; override;
@@ -96,9 +118,11 @@ Type
     Procedure AddAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
     Procedure AddAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
     Procedure RemoveAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
     Procedure RemoveAccounts(Const AccountKey : TAccountKey; accounts : Array of Cardinal);
     Function IndexOfAccountKey(Const AccountKey : TAccountKey) : Integer;
     Function IndexOfAccountKey(Const AccountKey : TAccountKey) : Integer;
-    Property AccountKeyList[index : Integer] : TList read GetAccountKeyList;
+    Property AccountKeyList[index : Integer] : TOrderedCardinalList read GetAccountKeyList;
     Property AccountKey[index : Integer] : TAccountKey read GetAccountKey;
     Property AccountKey[index : Integer] : TAccountKey read GetAccountKey;
     Function Count : Integer;
     Function Count : Integer;
+    Property SafeBox : TPCSafeBox read FAccountList;
+    Procedure Clear;
   End;
   End;
 
 
 
 
@@ -193,28 +217,6 @@ Type
     class Function ReadAnsiString(Stream: TStream; var value: AnsiString): Integer;
     class Function ReadAnsiString(Stream: TStream; var value: AnsiString): Integer;
   End;
   End;
 
 
-  TOrderedCardinalList = Class
-  private
-    FOrderedList : TList;
-    FDisabledsCount : Integer;
-    FModifiedWhileDisabled : Boolean;
-    FOnListChanged: TNotifyEvent;
-    Procedure NotifyChanged;
-  public
-    Constructor Create;
-    Destructor Destroy; override;
-    Function Add(Value : Cardinal) : Integer;
-    Procedure Remove(Value : Cardinal);
-    Procedure Clear;
-    Function Get(index : Integer) : Cardinal;
-    Function Count : Integer;
-    Function Find(const Value: Cardinal; var Index: Integer): Boolean;
-    Procedure Disable;
-    Procedure Enable;
-    Property OnListChanged : TNotifyEvent read FOnListChanged write FOnListChanged;
-    Procedure CopyFrom(Sender : TOrderedCardinalList);
-  End;
-
 Const
 Const
   CT_Account_NUL : TAccount = (account:0;accountkey:(EC_OpenSSL_NID:0;x:'';y:'');balance:0;updated_block:0;n_operation:0);
   CT_Account_NUL : TAccount = (account:0;accountkey:(EC_OpenSSL_NID:0;x:'';y:'');balance:0;updated_block:0;n_operation:0);
   CT_BlockAccount_NUL : TBlockAccount = (
   CT_BlockAccount_NUL : TBlockAccount = (
@@ -765,7 +767,7 @@ begin
   end;
   end;
   FBlockAccountsList.Clear;
   FBlockAccountsList.Clear;
   For i:=0 to FListOfOrderedAccountKeysList.count-1 do begin
   For i:=0 to FListOfOrderedAccountKeysList.count-1 do begin
-    TOrderedAccountKeysList( FListOfOrderedAccountKeysList[i] ).Clear(False);
+    TOrderedAccountKeysList( FListOfOrderedAccountKeysList[i] ).ClearAccounts(False);
   end;
   end;
   FBufferBlocksHash := '';
   FBufferBlocksHash := '';
   FTotalBalance := 0;
   FTotalBalance := 0;
@@ -1271,7 +1273,7 @@ end;
 Type
 Type
   TOrderedAccountKeyList = Record
   TOrderedAccountKeyList = Record
     rawaccountkey : TRawBytes;
     rawaccountkey : TRawBytes;
-    accounts : TList;
+    accounts_number : TOrderedCardinalList;
   end;
   end;
   POrderedAccountKeyList = ^TOrderedAccountKeyList;
   POrderedAccountKeyList = ^TOrderedAccountKeyList;
 
 
@@ -1287,7 +1289,7 @@ begin
   if Not Find(AccountKey,i) then begin
   if Not Find(AccountKey,i) then begin
     New(P);
     New(P);
     P^.rawaccountkey := TAccountComp.AccountKey2RawString(AccountKey);
     P^.rawaccountkey := TAccountComp.AccountKey2RawString(AccountKey);
-    P^.accounts := TList.Create;
+    P^.accounts_number := TOrderedCardinalList.Create;
     FOrderedAccountKeysList.Insert(i,P);
     FOrderedAccountKeysList.Insert(i,P);
     // Search this key in the AccountsList and add all...
     // Search this key in the AccountsList and add all...
     j := 0;
     j := 0;
@@ -1295,7 +1297,7 @@ begin
       For i:=0 to FAccountList.AccountsCount-1 do begin
       For i:=0 to FAccountList.AccountsCount-1 do begin
         If TAccountComp.Equal(FAccountList.Account(i).accountkey,AccountKey) then begin
         If TAccountComp.Equal(FAccountList.Account(i).accountkey,AccountKey) then begin
           // Note: P^.accounts will be ascending ordered due to "for i:=0 to ..."
           // Note: P^.accounts will be ascending ordered due to "for i:=0 to ..."
-          P^.accounts.Add(TObject(i));
+          P^.accounts_number.Add(i);
         end;
         end;
       end;
       end;
       TLog.NewLog(ltdebug,Classname,Format('Adding account key (%d of %d) %s',[j,FAccountList.AccountsCount,TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(AccountKey))]));
       TLog.NewLog(ltdebug,Classname,Format('Adding account key (%d of %d) %s',[j,FAccountList.AccountsCount,TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(AccountKey))]));
@@ -1307,40 +1309,37 @@ end;
 
 
 procedure TOrderedAccountKeysList.AddAccounts(const AccountKey: TAccountKey; accounts: array of Cardinal);
 procedure TOrderedAccountKeysList.AddAccounts(const AccountKey: TAccountKey; accounts: array of Cardinal);
 Var P : POrderedAccountKeyList;
 Var P : POrderedAccountKeyList;
-  i : Integer;
+  i,i2 : Integer;
 begin
 begin
   if Find(AccountKey,i) then begin
   if Find(AccountKey,i) then begin
     P :=  POrderedAccountKeyList(FOrderedAccountKeysList[i]);
     P :=  POrderedAccountKeyList(FOrderedAccountKeysList[i]);
   end else if (FAutoAddAll) then begin
   end else if (FAutoAddAll) then begin
     New(P);
     New(P);
     P^.rawaccountkey := TAccountComp.AccountKey2RawString(AccountKey);
     P^.rawaccountkey := TAccountComp.AccountKey2RawString(AccountKey);
-    P^.accounts := TList.Create;
+    P^.accounts_number := TOrderedCardinalList.Create;
     FOrderedAccountKeysList.Insert(i,P);
     FOrderedAccountKeysList.Insert(i,P);
   end else exit;
   end else exit;
   for i := Low(accounts) to High(accounts) do begin
   for i := Low(accounts) to High(accounts) do begin
-    If P^.accounts.IndexOf(TObject(accounts[i]))<0 then begin
-      // Add ordered
-      P^.accounts.Add(TObject(accounts[i]));
-    end;
-    {$IFDEF FPC}
-    P^.accounts.Sort(SortOrdered);
-    {$ELSE}
-    P^.accounts.SortList(SortOrdered);
-    {$ENDIF}
+    P^.accounts_number.Add(accounts[i]);
   end;
   end;
 end;
 end;
 
 
-procedure TOrderedAccountKeysList.Clear(RemoveAccountList : Boolean);
+procedure TOrderedAccountKeysList.Clear;
+begin
+  ClearAccounts(true);
+end;
+
+procedure TOrderedAccountKeysList.ClearAccounts(RemoveAccountList : Boolean);
 Var P : POrderedAccountKeyList;
 Var P : POrderedAccountKeyList;
   i : Integer;
   i : Integer;
 begin
 begin
   for i := 0 to FOrderedAccountKeysList.Count - 1 do begin
   for i := 0 to FOrderedAccountKeysList.Count - 1 do begin
     P := FOrderedAccountKeysList[i];
     P := FOrderedAccountKeysList[i];
     if RemoveAccountList then begin
     if RemoveAccountList then begin
-      P^.accounts.Free;
+      P^.accounts_number.Free;
       Dispose(P);
       Dispose(P);
     end else begin
     end else begin
-      P^.accounts.Clear;
+      P^.accounts_number.Clear;
     end;
     end;
   end;
   end;
   if RemoveAccountList then begin
   if RemoveAccountList then begin
@@ -1376,7 +1375,7 @@ begin
   if Assigned(FAccountList) then begin
   if Assigned(FAccountList) then begin
     FAccountList.FListOfOrderedAccountKeysList.Remove(Self);
     FAccountList.FListOfOrderedAccountKeysList.Remove(Self);
   end;
   end;
-  Clear(true);
+  ClearAccounts(true);
   FreeAndNil(FOrderedAccountKeysList);
   FreeAndNil(FOrderedAccountKeysList);
   inherited;
   inherited;
 end;
 end;
@@ -1413,9 +1412,9 @@ begin
   Result := TAccountComp.RawString2Accountkey(raw);
   Result := TAccountComp.RawString2Accountkey(raw);
 end;
 end;
 
 
-function TOrderedAccountKeysList.GetAccountKeyList(index: Integer): TList;
+function TOrderedAccountKeysList.GetAccountKeyList(index: Integer): TOrderedCardinalList;
 begin
 begin
-  Result := POrderedAccountKeyList(FOrderedAccountKeysList[index]).accounts;
+  Result := POrderedAccountKeyList(FOrderedAccountKeysList[index]).accounts_number;
 end;
 end;
 
 
 function TOrderedAccountKeysList.IndexOfAccountKey(const AccountKey: TAccountKey): Integer;
 function TOrderedAccountKeysList.IndexOfAccountKey(const AccountKey: TAccountKey): Integer;
@@ -1430,13 +1429,13 @@ begin
   if Not Find(AccountKey,i) then exit; // Nothing to do
   if Not Find(AccountKey,i) then exit; // Nothing to do
   P :=  POrderedAccountKeyList(FOrderedAccountKeysList[i]);
   P :=  POrderedAccountKeyList(FOrderedAccountKeysList[i]);
   for j := Low(accounts) to High(accounts) do begin
   for j := Low(accounts) to High(accounts) do begin
-    P^.accounts.Remove(TObject(accounts[j]));
+    P^.accounts_number.Remove(accounts[j]);
   end;
   end;
-  if (P^.accounts.Count=0) And (FAutoAddAll) then begin
+  if (P^.accounts_number.Count=0) And (FAutoAddAll) then begin
     // Remove from list
     // Remove from list
     FOrderedAccountKeysList.Delete(i);
     FOrderedAccountKeysList.Delete(i);
     // Free it
     // Free it
-    P^.accounts.free;
+    P^.accounts_number.free;
     Dispose(P);
     Dispose(P);
   end;
   end;
 end;
 end;
@@ -1450,7 +1449,7 @@ begin
   // Remove from list
   // Remove from list
   FOrderedAccountKeysList.Delete(i);
   FOrderedAccountKeysList.Delete(i);
   // Free it
   // Free it
-  P^.accounts.free;
+  P^.accounts_number.free;
   Dispose(P);
   Dispose(P);
 end;
 end;
 
 

+ 421 - 256
Units/PascalCoin/UBlockChain.pas

@@ -132,14 +132,19 @@ Type
   TOperationResume = Record
   TOperationResume = Record
     Block : Cardinal;
     Block : Cardinal;
     NOpInsideBlock : Integer;
     NOpInsideBlock : Integer;
+    OpType : Word;
     time : Cardinal;
     time : Cardinal;
     AffectedAccount : Cardinal;
     AffectedAccount : Cardinal;
+    SenderAccount : Int64; // only used when is a transaction
+    DestAccount : Int64; // only used when is a transaction
+    newKey : TAccountKey;
     OperationTxt : AnsiString;
     OperationTxt : AnsiString;
     Amount : Int64;
     Amount : Int64;
     Fee : Int64;
     Fee : Int64;
     Balance : Int64;
     Balance : Int64;
     OriginalPayload : TRawBytes;
     OriginalPayload : TRawBytes;
     PrintablePayload : AnsiString;
     PrintablePayload : AnsiString;
+    OperationHash : TRawBytes;
   end;
   end;
 
 
   TOperationsResumeList = Class
   TOperationsResumeList = Class
@@ -156,6 +161,8 @@ Type
     Property OperationResume[index : Integer] : TOperationResume read GetOperationResume; default;
     Property OperationResume[index : Integer] : TOperationResume read GetOperationResume; default;
   End;
   End;
 
 
+  { TPCOperation }
+
   TPCOperation = Class
   TPCOperation = Class
   Private
   Private
     Ftag: integer;
     Ftag: integer;
@@ -170,11 +177,12 @@ Type
     function LoadFromStream(Stream: TStream): Boolean; virtual; abstract;
     function LoadFromStream(Stream: TStream): Boolean; virtual; abstract;
     procedure AffectedAccounts(list : TList); virtual; abstract;
     procedure AffectedAccounts(list : TList); virtual; abstract;
     class function OpType: Byte; virtual; abstract;
     class function OpType: Byte; virtual; abstract;
-    Class Function OperationToOperationResume(Operation : TPCOperation; Affected_account_number : Cardinal; var OperationResume : TOperationResume) : Boolean;
+    Class Function OperationToOperationResume(Block : Cardinal; Operation : TPCOperation; Affected_account_number : Cardinal; var OperationResume : TOperationResume) : Boolean;
     function OperationAmount : Int64; virtual; abstract;
     function OperationAmount : Int64; virtual; abstract;
     function OperationFee: UInt64; virtual; abstract;
     function OperationFee: UInt64; virtual; abstract;
     function OperationPayload : TRawBytes; virtual; abstract;
     function OperationPayload : TRawBytes; virtual; abstract;
     function SenderAccount : Cardinal; virtual; abstract;
     function SenderAccount : Cardinal; virtual; abstract;
+    function N_Operation : Cardinal; virtual; abstract;
     Property tag : integer read Ftag Write Ftag;
     Property tag : integer read Ftag Write Ftag;
     // Property AuxBalance : Int64 read FAuxBalance Write FAuxBalance; Deprecated, not used
     // Property AuxBalance : Int64 read FAuxBalance Write FAuxBalance; Deprecated, not used
     // New Build 1.0.8 To save previous updated block in storage
     // New Build 1.0.8 To save previous updated block in storage
@@ -182,6 +190,8 @@ Type
     function LoadFromStorage(Stream: TStream): Boolean;
     function LoadFromStorage(Stream: TStream): Boolean;
     Property Previous_Sender_updated_block : Cardinal read FPrevious_Sender_updated_block;
     Property Previous_Sender_updated_block : Cardinal read FPrevious_Sender_updated_block;
     Property Previous_Destination_updated_block : Cardinal read FPrevious_Destination_updated_block;
     Property Previous_Destination_updated_block : Cardinal read FPrevious_Destination_updated_block;
+    Class function OperationHash(op : TPCOperation; Block : Cardinal) : TRawBytes;
+    Class function DecodeOperationHash(Const operationHash : TRawBytes; var block, account,n_operation : Cardinal) : Boolean;
   End;
   End;
 
 
   TOperationsHashTree = Class
   TOperationsHashTree = Class
@@ -205,6 +215,8 @@ Type
     Property TotalFee : Int64 read FTotalFee;
     Property TotalFee : Int64 read FTotalFee;
   End;
   End;
 
 
+  { TPCOperationsComp }
+
   TPCOperationsComp = Class(TComponent)
   TPCOperationsComp = Class(TComponent)
   private
   private
     FBank: TPCBank;
     FBank: TPCBank;
@@ -217,6 +229,7 @@ Type
     FIsOnlyOperationBlock: Boolean;
     FIsOnlyOperationBlock: Boolean;
     FStreamPoW : TMemoryStream;
     FStreamPoW : TMemoryStream;
     FDisableds : Integer;
     FDisableds : Integer;
+    FOperationsLock : TCriticalSection;
     function GetOperation(index: Integer): TPCOperation;
     function GetOperation(index: Integer): TPCOperation;
     procedure SetBank(const value: TPCBank);
     procedure SetBank(const value: TPCBank);
     procedure SetnOnce(const value: Cardinal);
     procedure SetnOnce(const value: Cardinal);
@@ -260,6 +273,8 @@ Type
     //
     //
     Function ValidateOperationBlock(var errors : AnsiString) : Boolean;
     Function ValidateOperationBlock(var errors : AnsiString) : Boolean;
     Property IsOnlyOperationBlock : Boolean read FIsOnlyOperationBlock;
     Property IsOnlyOperationBlock : Boolean read FIsOnlyOperationBlock;
+    Procedure Lock;
+    Procedure Unlock;
     //
     //
     Procedure SanitizeOperations;
     Procedure SanitizeOperations;
 
 
@@ -377,7 +392,7 @@ Type
   End;
   End;
 
 
 Const
 Const
-  CT_TOperationResume_NUL : TOperationResume = (Block:0;NOpInsideBlock:-1;time:0;AffectedAccount:0; OperationTxt:'';Amount:0;Fee:0;Balance:0;OriginalPayload:'';PrintablePayload:'');
+  CT_TOperationResume_NUL : TOperationResume = (Block:0;NOpInsideBlock:-1;OpType:0;time:0;AffectedAccount:0;SenderAccount:-1;DestAccount:-1;newKey:(EC_OpenSSL_NID:0;x:'';y:'');OperationTxt:'';Amount:0;Fee:0;Balance:0;OriginalPayload:'';PrintablePayload:'';OperationHash:'');
 
 
   CT_OperationBlock_NUL : TOperationBlock = (block:0;account_key:(EC_OpenSSL_NID:0;x:'';y:'');reward:0;fee:0;protocol_version:0;
   CT_OperationBlock_NUL : TOperationBlock = (block:0;account_key:(EC_OpenSSL_NID:0;x:'';y:'');reward:0;fee:0;protocol_version:0;
     protocol_available:0;timestamp:0;compact_target:0;nonce:0;block_payload:'';initial_safe_box_hash:'';operations_hash:'';proof_of_work:'');
     protocol_available:0;timestamp:0;compact_target:0;nonce:0;block_payload:'';initial_safe_box_hash:'';operations_hash:'';proof_of_work:'');
@@ -385,7 +400,8 @@ Const
 implementation
 implementation
 
 
 uses
 uses
-  Messages, SysUtils, Variants, {Graphics,}
+  {Messages, }
+  SysUtils, Variants, {Graphics,}
   {Controls, Forms,}
   {Controls, Forms,}
   Dialogs, {StdCtrls,}
   Dialogs, {StdCtrls,}
   UTime, UConst, UOpTransaction;
   UTime, UConst, UOpTransaction;
@@ -942,27 +958,33 @@ end;
 var
 var
   _OperationsClass: Array of TPCOperationClass;
   _OperationsClass: Array of TPCOperationClass;
 
 
-Function TPCOperationsComp.AddOperation(Execute : Boolean; op: TPCOperation; var errors: AnsiString): Boolean;
+function TPCOperationsComp.AddOperation(Execute: Boolean; op: TPCOperation;
+  var errors: AnsiString): Boolean;
 Begin
 Begin
-  errors := '';
-  Result := False;
-  if Execute then begin
-    if (FBank = Nil) then begin
-      errors := 'No Bank';
-      exit;
-    end;
-    if (FBank.BlocksCount<>OperationBlock.block) then begin
-      errors := 'Bank blockcount<>OperationBlock.Block';
-      exit;
+  Lock;
+  Try
+    errors := '';
+    Result := False;
+    if Execute then begin
+      if (FBank = Nil) then begin
+        errors := 'No Bank';
+        exit;
+      end;
+      if (FBank.BlocksCount<>OperationBlock.block) then begin
+        errors := 'Bank blockcount<>OperationBlock.Block';
+        exit;
+      end;
+      // Only process when in current address, prevent do it when reading operations from file
+      Result := op.DoOperation(SafeBoxTransaction, errors);
+    end else Result := true;
+    if Result then begin
+      FOperationsHashTree.AddOperationToHashTree(op);
+      FOperationBlock.fee := FOperationBlock.fee + op.OperationFee;
+      FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
+      if FDisableds<=0 then Calc_Digest_Parts;
     end;
     end;
-    // Only process when in current address, prevent do it when reading operations from file
-    Result := op.DoOperation(SafeBoxTransaction, errors);
-  end else Result := true;
-  if Result then begin
-    FOperationsHashTree.AddOperationToHashTree(op);
-    FOperationBlock.fee := FOperationBlock.fee + op.OperationFee;
-    FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
-    if FDisableds<=0 then Calc_Digest_Parts;
+  finally
+    Unlock;
   end;
   end;
 End;
 End;
 
 
@@ -971,24 +993,30 @@ function TPCOperationsComp.AddOperations(operations: TOperationsHashTree; var er
 Var i : Integer;
 Var i : Integer;
   e : AnsiString;
   e : AnsiString;
 begin
 begin
-  Result := 0;
-  errors := '';
-  if operations=FOperationsHashTree then exit;
-  inc(FDisableds);
+  Lock;
   try
   try
-    for i := 0 to operations.OperationsCount - 1 do begin
-      if not AddOperation(true,operations.GetOperation(i),e) then begin
-        if (errors<>'') then errors := errors+' ';
-        errors := errors + 'Op'+inttostr(i+1)+'/'+inttostr(operations.OperationsCount)+':'+e;
-      end else inc(Result);
+    Result := 0;
+    errors := '';
+    if operations=FOperationsHashTree then exit;
+    inc(FDisableds);
+    try
+      for i := 0 to operations.OperationsCount - 1 do begin
+        if not AddOperation(true,operations.GetOperation(i),e) then begin
+          if (errors<>'') then errors := errors+' ';
+          errors := errors + 'Op'+inttostr(i+1)+'/'+inttostr(operations.OperationsCount)+':'+e;
+        end else inc(Result);
+      end;
+    finally
+      Dec(FDisableds);
+      Calc_Digest_Parts;
     end;
     end;
   finally
   finally
-    Dec(FDisableds);
-    Calc_Digest_Parts;
+    Unlock;
   end;
   end;
 end;
 end;
 
 
-Procedure TPCOperationsComp.CalcProofOfWork(fullcalculation : Boolean; var PoW: TRawBytes);
+procedure TPCOperationsComp.CalcProofOfWork(fullcalculation: Boolean;
+  var PoW: TRawBytes);
 begin
 begin
   if fullcalculation then begin
   if fullcalculation then begin
     Calc_Digest_Parts;
     Calc_Digest_Parts;
@@ -1034,6 +1062,7 @@ end;
 
 
 procedure TPCOperationsComp.Clear(DeleteOperations : Boolean);
 procedure TPCOperationsComp.Clear(DeleteOperations : Boolean);
 begin
 begin
+  Lock;
   Try
   Try
     if DeleteOperations then begin
     if DeleteOperations then begin
       FOperationsHashTree.ClearHastThree;
       FOperationsHashTree.ClearHastThree;
@@ -1066,22 +1095,33 @@ begin
     FOperationBlock.protocol_available := CT_BlockChain_Protocol_Available;
     FOperationBlock.protocol_available := CT_BlockChain_Protocol_Available;
     FIsOnlyOperationBlock := false;
     FIsOnlyOperationBlock := false;
   Finally
   Finally
-    CalcProofOfWork(true,FOperationBlock.proof_of_work);
+    try
+      CalcProofOfWork(true,FOperationBlock.proof_of_work);
+    finally
+      Unlock;
+    end;
   End;
   End;
 end;
 end;
 
 
 procedure TPCOperationsComp.CopyFrom(Operations: TPCOperationsComp);
 procedure TPCOperationsComp.CopyFrom(Operations: TPCOperationsComp);
 begin
 begin
   if Self=Operations then exit;
   if Self=Operations then exit;
-  FOperationBlock := Operations.FOperationBlock;
-  FIsOnlyOperationBlock := Operations.FIsOnlyOperationBlock;
-  FOperationsHashTree.CopyFromHashTree(Operations.FOperationsHashTree);
-  if Assigned(FSafeBoxTransaction) And Assigned(Operations.FSafeBoxTransaction) then begin
-    FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
+  Lock;
+  Operations.Lock;
+  Try
+    FOperationBlock := Operations.FOperationBlock;
+    FIsOnlyOperationBlock := Operations.FIsOnlyOperationBlock;
+    FOperationsHashTree.CopyFromHashTree(Operations.FOperationsHashTree);
+    if Assigned(FSafeBoxTransaction) And Assigned(Operations.FSafeBoxTransaction) then begin
+      FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
+    end;
+    FDigest_Part1 := Operations.FDigest_Part1;
+    FDigest_Part2_Payload := Operations.FDigest_Part2_Payload;
+    FDigest_Part3 := Operations.FDigest_Part3;
+  finally
+    Operations.Unlock;
+    Unlock;
   end;
   end;
-  FDigest_Part1 := Operations.FDigest_Part1;
-  FDigest_Part2_Payload := Operations.FDigest_Part2_Payload;
-  FDigest_Part3 := Operations.FDigest_Part3;
 end;
 end;
 
 
 function TPCOperationsComp.CopyFromAndValidate(Operations: TPCOperationsComp; var errors: AnsiString): Boolean;
 function TPCOperationsComp.CopyFromAndValidate(Operations: TPCOperationsComp; var errors: AnsiString): Boolean;
@@ -1089,44 +1129,54 @@ Var i : Integer;
   e : AnsiString;
   e : AnsiString;
   op : TPCOperation;
   op : TPCOperation;
 begin
 begin
-  errors := '';
-  if Self=Operations then begin
-    result := true;
-    exit;
-  end else Result := false;
-  Clear(true);
-  if Operations.IsOnlyOperationBlock then begin
-    errors := 'Operations is only an operation block';
-    exit;
-  end;
-  FOperationBlock := Operations.OperationBlock;
-  for i := 0 to Operations.OperationsHashTree.OperationsCount-1 do begin
-    op := Operations.OperationsHashTree.GetOperation(i);
-    if Not op.DoOperation(SafeBoxTransaction,e) then begin
-      errors := 'Error executing operation '+inttostr(i+1)+'/'+Inttostr(Operations.OperationsHashTree.OperationsCount)+':'+e;
+  Lock;
+  Try
+    errors := '';
+    if Self=Operations then begin
+      result := true;
+      exit;
+    end else Result := false;
+    Clear(true);
+    if Operations.IsOnlyOperationBlock then begin
+      errors := 'Operations is only an operation block';
       exit;
       exit;
     end;
     end;
-    FOperationsHashTree.AddOperationToHashTree(op);
+    FOperationBlock := Operations.OperationBlock;
+    for i := 0 to Operations.OperationsHashTree.OperationsCount-1 do begin
+      op := Operations.OperationsHashTree.GetOperation(i);
+      if Not op.DoOperation(SafeBoxTransaction,e) then begin
+        errors := 'Error executing operation '+inttostr(i+1)+'/'+Inttostr(Operations.OperationsHashTree.OperationsCount)+':'+e;
+        exit;
+      end;
+      FOperationsHashTree.AddOperationToHashTree(op);
+    end;
+    Result := ValidateOperationBlock(errors);
+  finally
+    Unlock;
   end;
   end;
-  Result := ValidateOperationBlock(errors);
 end;
 end;
 
 
 procedure TPCOperationsComp.CopyFromExceptAddressKey(Operations: TPCOperationsComp);
 procedure TPCOperationsComp.CopyFromExceptAddressKey(Operations: TPCOperationsComp);
 var lastopb : TOperationBlock;
 var lastopb : TOperationBlock;
 begin
 begin
-  if Self=Operations then exit;
-  lastopb := FOperationBlock;
-  FOperationBlock := Operations.FOperationBlock;
-  FOperationBlock.account_key := lastopb.account_key; // Except AddressKey
-  FOperationBlock.compact_target := Bank.GetActualCompactTargetHash;
-  FIsOnlyOperationBlock := Operations.FIsOnlyOperationBlock;
-  FOperationsHashTree.CopyFromHashTree(Operations.FOperationsHashTree);
-  FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
-  if Assigned(FSafeBoxTransaction) And Assigned(Operations.FSafeBoxTransaction) then begin
-    FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
+  Lock;
+  Try
+    if Self=Operations then exit;
+    lastopb := FOperationBlock;
+    FOperationBlock := Operations.FOperationBlock;
+    FOperationBlock.account_key := lastopb.account_key; // Except AddressKey
+    FOperationBlock.compact_target := Bank.GetActualCompactTargetHash;
+    FIsOnlyOperationBlock := Operations.FIsOnlyOperationBlock;
+    FOperationsHashTree.CopyFromHashTree(Operations.FOperationsHashTree);
+    FOperationBlock.operations_hash := FOperationsHashTree.HashTree;
+    if Assigned(FSafeBoxTransaction) And Assigned(Operations.FSafeBoxTransaction) then begin
+      FSafeBoxTransaction.CopyFrom(Operations.FSafeBoxTransaction);
+    end;
+    // Recalc all
+    CalcProofOfWork(true,FOperationBlock.proof_of_work);
+  finally
+    Unlock;
   end;
   end;
-  // Recalc all
-  CalcProofOfWork(true,FOperationBlock.proof_of_work);
 end;
 end;
 
 
 function TPCOperationsComp.Count: Integer;
 function TPCOperationsComp.Count: Integer;
@@ -1137,6 +1187,7 @@ end;
 constructor TPCOperationsComp.Create(AOwner: TComponent);
 constructor TPCOperationsComp.Create(AOwner: TComponent);
 begin
 begin
   inherited Create(AOwner);
   inherited Create(AOwner);
+  FOperationsLock := TCriticalSection.Create;
   FDisableds := 0;
   FDisableds := 0;
   FStreamPoW := TMemoryStream.Create;
   FStreamPoW := TMemoryStream.Create;
   FStreamPoW.Position := 0;
   FStreamPoW.Position := 0;
@@ -1151,12 +1202,17 @@ end;
 
 
 destructor TPCOperationsComp.Destroy;
 destructor TPCOperationsComp.Destroy;
 begin
 begin
-  Clear(true);
-  FreeAndNil(FOperationsHashTree);
-  if Assigned(FSafeBoxTransaction) then begin
-    FreeAndNil(FSafeBoxTransaction);
+  FOperationsLock.Acquire;
+  try
+    Clear(true);
+    FreeAndNil(FOperationsHashTree);
+    if Assigned(FSafeBoxTransaction) then begin
+      FreeAndNil(FSafeBoxTransaction);
+    end;
+    FreeAndNil(FStreamPoW);
+  finally
+    FreeAndNil(FOperationsLock);
   end;
   end;
-  FreeAndNil(FStreamPoW);
   inherited;
   inherited;
 end;
 end;
 
 
@@ -1277,92 +1333,97 @@ Var
   OpClass: TPCOperationClass;
   OpClass: TPCOperationClass;
   errors2 : AnsiString;
   errors2 : AnsiString;
 begin
 begin
-  Clear(true);
-  Result := False;
-  //
-  errors := 'Invalid protocol structure. Check application version!';
-  if (Stream.Size - Stream.Position < 5) then exit;
-  Stream.Read(soob,1);
-  // About soob var:
-  // In build prior to 1.0.4 soob only can have 2 values: 0 or 1
-  // In build 1.0.4 soob can has 2 more values: 2 or 3
-  // In future, old values 0 and 1 will no longer be used!
-  // - Value 0 and 2 means that contains also operations
-  // - Value 1 and 3 means that only contains operationblock info
-  // - Value 2 and 3 means that contains protocol info prior to block number
-  if (soob=0) or (soob=2) then FIsOnlyOperationBlock:=false
-  else if (soob=1) or (soob=3) then FIsOnlyOperationBlock:=true
-  else begin
-    errors := 'Invalid value in protocol header! Found:'+inttostr(soob)+' - Check if your application version is Ok';
-    exit;
-  end;
+  Lock;
+  Try
+    Clear(true);
+    Result := False;
+    //
+    errors := 'Invalid protocol structure. Check application version!';
+    if (Stream.Size - Stream.Position < 5) then exit;
+    Stream.Read(soob,1);
+    // About soob var:
+    // In build prior to 1.0.4 soob only can have 2 values: 0 or 1
+    // In build 1.0.4 soob can has 2 more values: 2 or 3
+    // In future, old values 0 and 1 will no longer be used!
+    // - Value 0 and 2 means that contains also operations
+    // - Value 1 and 3 means that only contains operationblock info
+    // - Value 2 and 3 means that contains protocol info prior to block number
+    if (soob=0) or (soob=2) then FIsOnlyOperationBlock:=false
+    else if (soob=1) or (soob=3) then FIsOnlyOperationBlock:=true
+    else begin
+      errors := 'Invalid value in protocol header! Found:'+inttostr(soob)+' - Check if your application version is Ok';
+      exit;
+    end;
 
 
-  if (soob=2) or (soob=3) then begin
-    Stream.Read(FOperationBlock.protocol_version, Sizeof(FOperationBlock.protocol_version));
-    Stream.Read(FOperationBlock.protocol_available, Sizeof(FOperationBlock.protocol_available));
-  end;
+    if (soob=2) or (soob=3) then begin
+      Stream.Read(FOperationBlock.protocol_version, Sizeof(FOperationBlock.protocol_version));
+      Stream.Read(FOperationBlock.protocol_available, Sizeof(FOperationBlock.protocol_available));
+    end;
 
 
-  if Stream.Read(FOperationBlock.block, Sizeof(FOperationBlock.block))<0 then exit;
-
-  if TStreamOp.ReadAnsiString(Stream, m) < 0 then exit;
-  FOperationBlock.account_key := TAccountComp.RawString2Accountkey(m);
-  if Stream.Read(FOperationBlock.reward, Sizeof(FOperationBlock.reward)) < 0 then exit;
-  if Stream.Read(FOperationBlock.fee, Sizeof(FOperationBlock.fee)) < 0 then exit;
-  if Stream.Read(FOperationBlock.timestamp, Sizeof(FOperationBlock.timestamp)) < 0 then exit;
-  if Stream.Read(FOperationBlock.compact_target, Sizeof(FOperationBlock.compact_target)) < 0 then exit;
-  if Stream.Read(FOperationBlock.nonce, Sizeof(FOperationBlock.nonce)) < 0 then exit;
-  if TStreamOp.ReadAnsiString(Stream, FOperationBlock.block_payload) < 0 then exit;
-  if TStreamOp.ReadAnsiString(Stream, FOperationBlock.initial_safe_box_hash) < 0 then exit;
-  if TStreamOp.ReadAnsiString(Stream, FOperationBlock.operations_hash) < 0 then exit;
-  if TStreamOp.ReadAnsiString(Stream, FOperationBlock.proof_of_work) < 0 then exit;
-  If FIsOnlyOperationBlock then begin
-    Result := true;
-    exit;
-  end;
-  // Fee will be calculated for each operation. Set it to 0 and check later for integrity
-  lastfee := OperationBlock.fee;
-  FOperationBlock.fee := 0;
-  Stream.Read(c, 4);
-  // c = operations count
-  for i := 1 to c do begin
-    errors := 'Invalid operation structure ' + inttostr(i) + '/' + inttostr(c);
-    if Stream.Size - Stream.Position < 4 then exit;
-    Stream.Read(OpType, 4);
-    j := IndexOfOperationClassByOpType(OpType);
-    if j >= 0 then
-      OpClass := _OperationsClass[j]
-    else
-      OpClass := Nil;
-    if Not Assigned(OpClass) then begin
-      errors := errors + ' optype not valid:' + InttoHex(OpType, 4);
+    if Stream.Read(FOperationBlock.block, Sizeof(FOperationBlock.block))<0 then exit;
+
+    if TStreamOp.ReadAnsiString(Stream, m) < 0 then exit;
+    FOperationBlock.account_key := TAccountComp.RawString2Accountkey(m);
+    if Stream.Read(FOperationBlock.reward, Sizeof(FOperationBlock.reward)) < 0 then exit;
+    if Stream.Read(FOperationBlock.fee, Sizeof(FOperationBlock.fee)) < 0 then exit;
+    if Stream.Read(FOperationBlock.timestamp, Sizeof(FOperationBlock.timestamp)) < 0 then exit;
+    if Stream.Read(FOperationBlock.compact_target, Sizeof(FOperationBlock.compact_target)) < 0 then exit;
+    if Stream.Read(FOperationBlock.nonce, Sizeof(FOperationBlock.nonce)) < 0 then exit;
+    if TStreamOp.ReadAnsiString(Stream, FOperationBlock.block_payload) < 0 then exit;
+    if TStreamOp.ReadAnsiString(Stream, FOperationBlock.initial_safe_box_hash) < 0 then exit;
+    if TStreamOp.ReadAnsiString(Stream, FOperationBlock.operations_hash) < 0 then exit;
+    if TStreamOp.ReadAnsiString(Stream, FOperationBlock.proof_of_work) < 0 then exit;
+    If FIsOnlyOperationBlock then begin
+      Result := true;
       exit;
       exit;
     end;
     end;
-    errors := 'Invalid operation ' + inttostr(i) + '/' + inttostr(c)+' Class:'+OpClass.ClassName;
-    bcop := OpClass.Create;
-    Try
-      if LoadingFromStorage then begin
-        If not bcop.LoadFromStorage(Stream) then exit;
-      end else if not bcop.LoadFromStream(Stream) then begin
+    // Fee will be calculated for each operation. Set it to 0 and check later for integrity
+    lastfee := OperationBlock.fee;
+    FOperationBlock.fee := 0;
+    Stream.Read(c, 4);
+    // c = operations count
+    for i := 1 to c do begin
+      errors := 'Invalid operation structure ' + inttostr(i) + '/' + inttostr(c);
+      if Stream.Size - Stream.Position < 4 then exit;
+      Stream.Read(OpType, 4);
+      j := IndexOfOperationClassByOpType(OpType);
+      if j >= 0 then
+        OpClass := _OperationsClass[j]
+      else
+        OpClass := Nil;
+      if Not Assigned(OpClass) then begin
+        errors := errors + ' optype not valid:' + InttoHex(OpType, 4);
         exit;
         exit;
       end;
       end;
-      if Not AddOperation(false,bcop, errors2) then begin
-        errors := errors + ' '+errors2+' '+bcop.ToString;
-        exit;
+      errors := 'Invalid operation ' + inttostr(i) + '/' + inttostr(c)+' Class:'+OpClass.ClassName;
+      bcop := OpClass.Create;
+      Try
+        if LoadingFromStorage then begin
+          If not bcop.LoadFromStorage(Stream) then exit;
+        end else if not bcop.LoadFromStream(Stream) then begin
+          exit;
+        end;
+        if Not AddOperation(false,bcop, errors2) then begin
+          errors := errors + ' '+errors2+' '+bcop.ToString;
+          exit;
+        end;
+      Finally
+        FreeAndNil(bcop);
       end;
       end;
-    Finally
-      FreeAndNil(bcop);
     end;
     end;
-  end;
-  // Validation control:
-  if (lastfee<>OperationBlock.fee) then begin
-    errors := 'Corrupted operations fee old:'+inttostr(lastfee)+' new:'+inttostr(OperationBlock.fee);
-    for i := 0 to FOperationsHashTree.OperationsCount - 1 do begin
-      errors := errors + ' Op'+inttostr(i+1)+':'+FOperationsHashTree.GetOperation(i).ToString;
+    // Validation control:
+    if (lastfee<>OperationBlock.fee) then begin
+      errors := 'Corrupted operations fee old:'+inttostr(lastfee)+' new:'+inttostr(OperationBlock.fee);
+      for i := 0 to FOperationsHashTree.OperationsCount - 1 do begin
+        errors := errors + ' Op'+inttostr(i+1)+':'+FOperationsHashTree.GetOperation(i).ToString;
+      end;
+      Result := false;
+      exit;
     end;
     end;
-    Result := false;
-    exit;
+    Result := true;
+  finally
+    Unlock;
   end;
   end;
-  Result := true;
 end;
 end;
 
 
 procedure TPCOperationsComp.Notification(AComponent: TComponent;
 procedure TPCOperationsComp.Notification(AComponent: TComponent;
@@ -1405,6 +1466,7 @@ Var i,n,lastn : Integer;
   errors : AnsiString;
   errors : AnsiString;
   aux,aux2 : TOperationsHashTree;
   aux,aux2 : TOperationsHashTree;
 begin
 begin
+  Lock;
   Try
   Try
     FOperationBlock.timestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
     FOperationBlock.timestamp := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
     if Assigned(FBank) then begin
     if Assigned(FBank) then begin
@@ -1448,6 +1510,7 @@ begin
     End;
     End;
   Finally
   Finally
     CalcProofOfWork(true,FOperationBlock.proof_of_work);
     CalcProofOfWork(true,FOperationBlock.proof_of_work);
+    Unlock;
   End;
   End;
   if (n>0) then begin
   if (n>0) then begin
     TLog.NewLog(ltdebug,Classname,Format('Sanitize operations (before %d - after %d)',[lastn,n]));
     TLog.NewLog(ltdebug,Classname,Format('Sanitize operations (before %d - after %d)',[lastn,n]));
@@ -1472,54 +1535,63 @@ Var
   bcop: TPCOperation;
   bcop: TPCOperation;
   bcops, errors: AnsiString;
   bcops, errors: AnsiString;
 begin
 begin
-  //
-  if save_only_OperationBlock then begin
-    if (FOperationBlock.protocol_version=1) And (FOperationBlock.protocol_available=0) then soob := 1
-    else soob := 3;
-  end else begin
-    if (FOperationBlock.protocol_version=1) And (FOperationBlock.protocol_available=0) then soob := 0
-    else soob := 2;
-  end;
-  Stream.Write(soob,1);
-  if (soob>=2) then begin
-    Stream.Write(FOperationBlock.protocol_version, Sizeof(FOperationBlock.protocol_version));
-    Stream.Write(FOperationBlock.protocol_available, Sizeof(FOperationBlock.protocol_available));
-  end;
-  //
-  Stream.Write(FOperationBlock.block, Sizeof(FOperationBlock.block));
-  //
-  TStreamOp.WriteAnsiString(Stream,TAccountComp.AccountKey2RawString(FOperationBlock.account_key));
-  Stream.Write(FOperationBlock.reward, Sizeof(FOperationBlock.reward));
-  Stream.Write(FOperationBlock.fee, Sizeof(FOperationBlock.fee));
-  Stream.Write(FOperationBlock.timestamp, Sizeof(FOperationBlock.timestamp));
-  Stream.Write(FOperationBlock.compact_target, Sizeof(FOperationBlock.compact_target));
-  Stream.Write(FOperationBlock.nonce, Sizeof(FOperationBlock.nonce));
-  TStreamOp.WriteAnsiString(Stream, FOperationBlock.block_payload);
-  TStreamOp.WriteAnsiString(Stream, FOperationBlock.initial_safe_box_hash);
-  TStreamOp.WriteAnsiString(Stream, FOperationBlock.operations_hash);
-  TStreamOp.WriteAnsiString(Stream, FOperationBlock.proof_of_work);
-  if (Not save_only_OperationBlock) then begin
-    c := Count;
-    Stream.Write(c, 4);
-    // c = operations count
-    for i := 1 to c do
-    begin
-      bcop := Operation[i - 1];
-      OpType := bcop.OpType;
-      Stream.write(OpType, 4);
-      if SaveToStorage then bcop.SaveToStorage(Stream)
-      else bcop.SaveToStream(Stream);
+  Lock;
+  Try
+    //
+    if save_only_OperationBlock then begin
+      if (FOperationBlock.protocol_version=1) And (FOperationBlock.protocol_available=0) then soob := 1
+      else soob := 3;
+    end else begin
+      if (FOperationBlock.protocol_version=1) And (FOperationBlock.protocol_available=0) then soob := 0
+      else soob := 2;
+    end;
+    Stream.Write(soob,1);
+    if (soob>=2) then begin
+      Stream.Write(FOperationBlock.protocol_version, Sizeof(FOperationBlock.protocol_version));
+      Stream.Write(FOperationBlock.protocol_available, Sizeof(FOperationBlock.protocol_available));
+    end;
+    //
+    Stream.Write(FOperationBlock.block, Sizeof(FOperationBlock.block));
+    //
+    TStreamOp.WriteAnsiString(Stream,TAccountComp.AccountKey2RawString(FOperationBlock.account_key));
+    Stream.Write(FOperationBlock.reward, Sizeof(FOperationBlock.reward));
+    Stream.Write(FOperationBlock.fee, Sizeof(FOperationBlock.fee));
+    Stream.Write(FOperationBlock.timestamp, Sizeof(FOperationBlock.timestamp));
+    Stream.Write(FOperationBlock.compact_target, Sizeof(FOperationBlock.compact_target));
+    Stream.Write(FOperationBlock.nonce, Sizeof(FOperationBlock.nonce));
+    TStreamOp.WriteAnsiString(Stream, FOperationBlock.block_payload);
+    TStreamOp.WriteAnsiString(Stream, FOperationBlock.initial_safe_box_hash);
+    TStreamOp.WriteAnsiString(Stream, FOperationBlock.operations_hash);
+    TStreamOp.WriteAnsiString(Stream, FOperationBlock.proof_of_work);
+    if (Not save_only_OperationBlock) then begin
+      c := Count;
+      Stream.Write(c, 4);
+      // c = operations count
+      for i := 1 to c do
+      begin
+        bcop := Operation[i - 1];
+        OpType := bcop.OpType;
+        Stream.write(OpType, 4);
+        if SaveToStorage then bcop.SaveToStorage(Stream)
+        else bcop.SaveToStream(Stream);
+      end;
     end;
     end;
+    Result := true;
+  finally
+    Unlock;
   end;
   end;
-  Result := true;
 end;
 end;
 
 
 procedure TPCOperationsComp.SetAccountKey(const value: TAccountKey);
 procedure TPCOperationsComp.SetAccountKey(const value: TAccountKey);
 begin
 begin
-  if TAccountComp.AccountKey2RawString(value)=TAccountComp.AccountKey2RawString(FOperationBlock.account_key) then exit;
-  FOperationBlock.account_key := value;
-//  Calc_Digest_Basic;
-  Calc_Digest_Parts;
+  Lock;
+  Try
+    if TAccountComp.AccountKey2RawString(value)=TAccountComp.AccountKey2RawString(FOperationBlock.account_key) then exit;
+    FOperationBlock.account_key := value;
+    Calc_Digest_Parts;
+  finally
+    Unlock;
+  end;
 end;
 end;
 
 
 procedure TPCOperationsComp.SetBank(const value: TPCBank);
 procedure TPCOperationsComp.SetBank(const value: TPCBank);
@@ -1539,95 +1611,130 @@ end;
 procedure TPCOperationsComp.SetBlockPayload(const Value: TRawBytes);
 procedure TPCOperationsComp.SetBlockPayload(const Value: TRawBytes);
 Var i : Integer;
 Var i : Integer;
 begin
 begin
-  if Value=FOperationBlock.block_payload then exit;
-  if Length(Value)>CT_MaxPayloadSize then Exit;
-  // Checking Miner Payload valid chars
-  for i := 1 to length(Value) do begin
-    if Not (Value[i] in [#32..#254]) then begin
-      exit;
+  Lock;
+  Try
+    if Value=FOperationBlock.block_payload then exit;
+    if Length(Value)>CT_MaxPayloadSize then Exit;
+    // Checking Miner Payload valid chars
+    for i := 1 to length(Value) do begin
+      if Not (Value[i] in [#32..#254]) then begin
+        exit;
+      end;
     end;
     end;
+    FOperationBlock.block_payload := Value;
+    CalcProofOfWork(true,FOperationBlock.proof_of_work);
+  finally
+    Unlock;
   end;
   end;
-  FOperationBlock.block_payload := Value;
-  CalcProofOfWork(true,FOperationBlock.proof_of_work);
 end;
 end;
 
 
 procedure TPCOperationsComp.SetnOnce(const value: Cardinal);
 procedure TPCOperationsComp.SetnOnce(const value: Cardinal);
 begin
 begin
-  FOperationBlock.nonce := value;
-  CalcProofOfWork(false,FOperationBlock.proof_of_work);
+  Lock;
+  Try
+    FOperationBlock.nonce := value;
+    CalcProofOfWork(false,FOperationBlock.proof_of_work);
+  finally
+    Unlock;
+  end;
 end;
 end;
 
 
 procedure TPCOperationsComp.Settimestamp(const value: Cardinal);
 procedure TPCOperationsComp.Settimestamp(const value: Cardinal);
 begin
 begin
-  if FOperationBlock.timestamp=Value then exit; // No change, nothing to do
-  FOperationBlock.timestamp := value;
-  CalcProofOfWork(false,FOperationBlock.proof_of_work);
+  Lock;
+  Try
+    if FOperationBlock.timestamp=Value then exit; // No change, nothing to do
+    FOperationBlock.timestamp := value;
+    CalcProofOfWork(false,FOperationBlock.proof_of_work);
+  finally
+    Unlock;
+  end;
 end;
 end;
 
 
 procedure TPCOperationsComp.UpdateTimestamp;
 procedure TPCOperationsComp.UpdateTimestamp;
 Var ts : Cardinal;
 Var ts : Cardinal;
 begin
 begin
-  ts := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
-  if Assigned(bank) then begin
-    If Bank.FLastOperationBlock.timestamp>ts then ts := Bank.FLastOperationBlock.timestamp;
+  Lock;
+  Try
+    ts := UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+    if Assigned(bank) then begin
+      If Bank.FLastOperationBlock.timestamp>ts then ts := Bank.FLastOperationBlock.timestamp;
+    end;
+    timestamp := ts;
+  finally
+    Unlock;
   end;
   end;
-  timestamp := ts;
 end;
 end;
 
 
 function TPCOperationsComp.ValidateOperationBlock(var errors : AnsiString): Boolean;
 function TPCOperationsComp.ValidateOperationBlock(var errors : AnsiString): Boolean;
 Var lastpow : AnsiString;
 Var lastpow : AnsiString;
   i : Integer;
   i : Integer;
 begin
 begin
-  Result := false;
-  lastpow := OperationBlock.proof_of_work;
-  // Execute SafeBoxTransaction operations:
-  SafeBoxTransaction.Rollback;
-  for i := 0 to Count - 1 do begin
-    If Not Operation[i].DoOperation(SafeBoxTransaction,errors) then begin
-      errors := 'Error executing operation '+inttostr(i+1)+'/'+inttostr(Count)+': '+errors;
+  Lock;
+  Try
+    Result := false;
+    lastpow := OperationBlock.proof_of_work;
+    // Execute SafeBoxTransaction operations:
+    SafeBoxTransaction.Rollback;
+    for i := 0 to Count - 1 do begin
+      If Not Operation[i].DoOperation(SafeBoxTransaction,errors) then begin
+        errors := 'Error executing operation '+inttostr(i+1)+'/'+inttostr(Count)+': '+errors;
+        exit;
+      end;
+    end;
+    // Checking Miner payload size
+    if length(BlockPayload)>CT_MaxPayloadSize then begin
+      errors := 'Invalid Miner Payload length: '+inttostr(Length(BlockPayload));
       exit;
       exit;
     end;
     end;
-  end;
-  // Checking Miner payload size
-  if length(BlockPayload)>CT_MaxPayloadSize then begin
-    errors := 'Invalid Miner Payload length: '+inttostr(Length(BlockPayload));
-    exit;
-  end;
-  // Checking Miner Payload valid chars
-  for i := 1 to length(BlockPayload) do begin
-    if Not (BlockPayload[i] in [#32..#254]) then begin
-      errors := 'Invalid Miner Payload character at pos '+inttostr(i)+' value:'+inttostr(ord(BlockPayload[i]));
+    // Checking Miner Payload valid chars
+    for i := 1 to length(BlockPayload) do begin
+      if Not (BlockPayload[i] in [#32..#254]) then begin
+        errors := 'Invalid Miner Payload character at pos '+inttostr(i)+' value:'+inttostr(ord(BlockPayload[i]));
+        exit;
+      end;
+    end;
+
+    CalcProofOfWork(true,FOperationBlock.proof_of_work);
+    if Not AnsiSameStr(OperationBlock.proof_of_work,lastpow) then begin
+      errors := 'Invalid Proof of work calculation';
+      exit;
+    end;
+    if FOperationsHashTree.HashTree<>OperationBlock.operations_hash then begin
+      errors := 'Invalid Operations Hash '+TCrypto.ToHexaString(OperationBlock.operations_hash)+'<>'+TCrypto.ToHexaString(FOperationsHashTree.HashTree);
       exit;
       exit;
     end;
     end;
-  end;
 
 
-  CalcProofOfWork(true,FOperationBlock.proof_of_work);
-  if Not AnsiSameStr(OperationBlock.proof_of_work,lastpow) then begin
-    errors := 'Invalid Proof of work calculation';
-    exit;
-  end;
-  if FOperationsHashTree.HashTree<>OperationBlock.operations_hash then begin
-    errors := 'Invalid Operations Hash '+TCrypto.ToHexaString(OperationBlock.operations_hash)+'<>'+TCrypto.ToHexaString(FOperationsHashTree.HashTree);
-    exit;
+    if Not TAccountComp.IsValidAccountKey(OperationBlock.account_key,errors) then begin
+      exit;
+    end;
+    if (OperationBlock.reward<>TPCBank.GetRewardForNewLine(OperationBlock.block)) then begin
+      errors := 'Invalid reward';
+      exit;
+    end;
+    if (SafeBoxTransaction.TotalFee<>OperationBlock.fee) then begin
+      errors := Format('Invalid fee integrity at SafeBoxTransaction. New Balance:(%d + fee %d = %d)  OperationBlock.fee:%d',
+        [
+          SafeBoxTransaction.TotalBalance,
+          SafeBoxTransaction.TotalFee,
+          SafeBoxTransaction.TotalBalance+SafeBoxTransaction.TotalFee,
+          OperationBlock.fee]);
+      exit;
+    end;
+    Result := true;
+  finally
+    Unlock;
   end;
   end;
+end;
 
 
-  if Not TAccountComp.IsValidAccountKey(OperationBlock.account_key,errors) then begin
-    exit;
-  end;
-  if (OperationBlock.reward<>TPCBank.GetRewardForNewLine(OperationBlock.block)) then begin
-    errors := 'Invalid reward';
-    exit;
-  end;
-  if (SafeBoxTransaction.TotalFee<>OperationBlock.fee) then begin
-    errors := Format('Invalid fee integrity at SafeBoxTransaction. New Balance:(%d + fee %d = %d)  OperationBlock.fee:%d',
-      [
-        SafeBoxTransaction.TotalBalance,
-        SafeBoxTransaction.TotalFee,
-        SafeBoxTransaction.TotalBalance+SafeBoxTransaction.TotalFee,
-        OperationBlock.fee]);
-    exit;
-  end;
-  Result := true;
+procedure TPCOperationsComp.Lock;
+begin
+  FOperationsLock.Acquire;
+end;
+
+procedure TPCOperationsComp.Unlock;
+begin
+  FOperationsLock.Release;
 end;
 end;
 
 
 { TPCBankNotify }
 { TPCBankNotify }
@@ -1908,17 +2015,72 @@ begin
   end;
   end;
 end;
 end;
 
 
-class function TPCOperation.OperationToOperationResume(Operation: TPCOperation;
+class function TPCOperation.OperationHash(op: TPCOperation; Block : Cardinal): TRawBytes;
+  { OperationHash is a 32 bytes value.
+    First 4 bytes (0..3) are Block in little endian
+    Next 4 bytes (4..7) are Account in little endian
+    Next 4 bytes (8..11) are N_Operation in little endian
+    Next 20 bytes (12..31) are a RipeMD160 of the operation buffer to hash
+    //
+    This format is easy to undecode because include account and n_operation
+   }
+var ms : TMemoryStream;
+  r : TRawBytes;
+  _a,_o : Cardinal;
+begin
+  ms := TMemoryStream.Create;
+  try
+    ms.Write(Block,4);
+    _a := op.SenderAccount;
+    _o := op.N_Operation;
+    ms.Write(_a,4);
+    ms.Write(_o,4);
+    ms.WriteBuffer(TCrypto.DoRipeMD160(op.GetOperationBufferToHash)[1],20);
+    SetLength(Result,ms.size);
+    ms.Position:=0;
+    ms.Read(Result[1],ms.size);
+  finally
+    ms.Free;
+  end;
+end;
+
+class function TPCOperation.DecodeOperationHash(const operationHash: TRawBytes;
+  var block, account, n_operation: Cardinal): Boolean;
+  { Decodes a previously generated OperationHash }
+var ms : TMemoryStream;
+begin
+  Result := false;
+  account:=0;
+  n_operation:=0;
+  if length(operationHash)<>32 then exit;
+  ms := TMemoryStream.Create;
+  try
+    ms.Write(operationHash[1],length(operationHash));
+    ms.position := 0;
+    ms.Read(block,4);
+    ms.Read(account,4);
+    ms.Read(n_operation,4);
+    Result := true;
+  finally
+    ms.free;
+  end;
+end;
+
+class function TPCOperation.OperationToOperationResume(Block : Cardinal; Operation: TPCOperation;
   Affected_account_number: Cardinal;
   Affected_account_number: Cardinal;
   var OperationResume: TOperationResume): Boolean;
   var OperationResume: TOperationResume): Boolean;
 Var spayload : AnsiString;
 Var spayload : AnsiString;
 begin
 begin
   OperationResume := CT_TOperationResume_NUL;
   OperationResume := CT_TOperationResume_NUL;
+  OperationResume.Block:=Block;
   OperationResume.Fee := (-1)*Int64(Operation.OperationFee);
   OperationResume.Fee := (-1)*Int64(Operation.OperationFee);
   OperationResume.AffectedAccount := Affected_account_number;
   OperationResume.AffectedAccount := Affected_account_number;
+  OperationResume.OpType:=Operation.OpType;
   Result := false;
   Result := false;
   case Operation.OpType of
   case Operation.OpType of
     CT_Op_Transaction : Begin
     CT_Op_Transaction : Begin
+      OperationResume.SenderAccount:=TOpTransaction(Operation).Data.sender;
+      OperationResume.DestAccount:=TOpTransaction(Operation).Data.target;
       if TOpTransaction(Operation).Data.sender=Affected_account_number then begin
       if TOpTransaction(Operation).Data.sender=Affected_account_number then begin
         OperationResume.OperationTxt := 'Transaction Sent to '+TAccountComp.AccountNumberToAccountTxtNumber(TOpTransaction(Operation).Data.target);
         OperationResume.OperationTxt := 'Transaction Sent to '+TAccountComp.AccountNumberToAccountTxtNumber(TOpTransaction(Operation).Data.target);
         OperationResume.Amount := Int64(TOpTransaction(Operation).Data.amount) * (-1);
         OperationResume.Amount := Int64(TOpTransaction(Operation).Data.amount) * (-1);
@@ -1931,6 +2093,7 @@ begin
       end else exit;
       end else exit;
     End;
     End;
     CT_Op_Changekey : Begin
     CT_Op_Changekey : Begin
+      OperationResume.newKey := TOpChangeKey(Operation).Data.new_accountkey;
       OperationResume.OperationTxt := 'Change Key to '+TAccountComp.GetECInfoTxt( TOpChangeKey(Operation).Data.new_accountkey.EC_OpenSSL_NID );
       OperationResume.OperationTxt := 'Change Key to '+TAccountComp.GetECInfoTxt( TOpChangeKey(Operation).Data.new_accountkey.EC_OpenSSL_NID );
       OperationResume.Fee := TOpChangeKey(Operation).Data.fee;
       OperationResume.Fee := TOpChangeKey(Operation).Data.fee;
       Result := true;
       Result := true;
@@ -1938,12 +2101,14 @@ begin
     CT_Op_Recover : Begin
     CT_Op_Recover : Begin
       OperationResume.OperationTxt := 'Recover founds';
       OperationResume.OperationTxt := 'Recover founds';
       OperationResume.Fee := TOpRecoverFounds(Operation).Data.fee;
       OperationResume.Fee := TOpRecoverFounds(Operation).Data.fee;
+      Result := true;
     End;
     End;
   else Exit;
   else Exit;
   end;
   end;
   OperationResume.OriginalPayload := Operation.OperationPayload;
   OperationResume.OriginalPayload := Operation.OperationPayload;
   If TCrypto.IsHumanReadable(OperationResume.OriginalPayload) then OperationResume.PrintablePayload := OperationResume.OriginalPayload
   If TCrypto.IsHumanReadable(OperationResume.OriginalPayload) then OperationResume.PrintablePayload := OperationResume.OriginalPayload
   else OperationResume.PrintablePayload := TCrypto.ToHexaString(OperationResume.OriginalPayload);
   else OperationResume.PrintablePayload := TCrypto.ToHexaString(OperationResume.OriginalPayload);
+  OperationResume.OperationHash:=TPCOperation.OperationHash(Operation,Block);
 end;
 end;
 
 
 function TPCOperation.SaveToStorage(Stream: TStream): Boolean;
 function TPCOperation.SaveToStorage(Stream: TStream): Boolean;

+ 3 - 1
Units/PascalCoin/UConst.pas

@@ -45,6 +45,7 @@ Const
 
 
   CT_NetServer_Port = {$IFDEF PRODUCTION}4004{$ELSE}{$IFDEF TESTNET}4104{$ELSE}{$ENDIF}{$ENDIF};
   CT_NetServer_Port = {$IFDEF PRODUCTION}4004{$ELSE}{$IFDEF TESTNET}4104{$ELSE}{$ENDIF}{$ENDIF};
   CT_JSONRPCMinerServer_Port = {$IFDEF PRODUCTION}4009{$ELSE}{$IFDEF TESTNET}4109{$ELSE}{$ENDIF}{$ENDIF};
   CT_JSONRPCMinerServer_Port = {$IFDEF PRODUCTION}4009{$ELSE}{$IFDEF TESTNET}4109{$ELSE}{$ENDIF}{$ENDIF};
+  CT_JSONRPC_Port = {$IFDEF PRODUCTION}4003{$ELSE}{$IFDEF TESTNET}4103{$ELSE}{$ENDIF}{$ENDIF};
   CT_AccountsPerBlock = 5;
   CT_AccountsPerBlock = 5;
 
 
   CT_NewLineSecondsAvg: Cardinal = {$IFDEF PRODUCTION}300{$ELSE}{$IFDEF TESTNET}30{$ELSE}{$ENDIF}{$ENDIF};
   CT_NewLineSecondsAvg: Cardinal = {$IFDEF PRODUCTION}300{$ELSE}{$IFDEF TESTNET}30{$ELSE}{$ENDIF}{$ENDIF};
@@ -68,6 +69,7 @@ Const
   CT_MinCompactTarget: Cardinal = {$IFDEF PRODUCTION}$19000000{$ELSE}{$IFDEF TESTNET}$17000000{$ELSE}{$ENDIF}{$ENDIF}; // First compact target of block 0
   CT_MinCompactTarget: Cardinal = {$IFDEF PRODUCTION}$19000000{$ELSE}{$IFDEF TESTNET}$17000000{$ELSE}{$ENDIF}{$ENDIF}; // First compact target of block 0
 
 
   CT_CalcNewTargetBlocksAverage: Cardinal = 100;
   CT_CalcNewTargetBlocksAverage: Cardinal = 100;
+  CT_MaxAccount : Cardinal = $FFFFFFFF;
   CT_MaxBlock : Cardinal = $FFFFFFFF;
   CT_MaxBlock : Cardinal = $FFFFFFFF;
 
 
   CT_MaxPayloadSize = 255; // Max payload size in bytes
   CT_MaxPayloadSize = 255; // Max payload size in bytes
@@ -101,7 +103,7 @@ Const
   CT_Op_Changekey = $02;
   CT_Op_Changekey = $02;
   CT_Op_Recover = $03;
   CT_Op_Recover = $03;
 
 
-  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.0.9'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
+  CT_ClientAppVersion : AnsiString = {$IFDEF PRODUCTION}'1.1.0'{$ELSE}{$IFDEF TESTNET}'TESTNET'{$ELSE}{$ENDIF}{$ENDIF};
 
 
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.ddns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
   CT_Discover_IPs =  'bpascal1.dynamic-dns.net;bpascal2.dynamic-dns.net;pascalcoin1.ddns.net;pascalcoin2.ddns.net;pascalcoin1.dynamic-dns.net;pascalcoin1.dns1.us';
 
 

+ 1 - 1
Units/PascalCoin/UCrypto.pas

@@ -22,7 +22,7 @@ unit UCrypto;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, UOpenSSL, UOpenSSLDef;
+  Classes, SysUtils, UOpenSSL, UOpenSSLdef;
 
 
 Type
 Type
   ECryptoException = Class(Exception);
   ECryptoException = Class(Exception);

+ 30 - 17
Units/PascalCoin/ULog.pas

@@ -52,11 +52,12 @@ type
   private
   private
     FLogDataList : TThreadList;
     FLogDataList : TThreadList;
     FOnNewLog: TNewLogEvent;
     FOnNewLog: TNewLogEvent;
+    FOnInThreadNewLog : TNewLogEvent;
     FFileStream : TFileStream;
     FFileStream : TFileStream;
     FFileName: AnsiString;
     FFileName: AnsiString;
     FSaveTypes: TLogTypes;
     FSaveTypes: TLogTypes;
     FThreadSafeLogEvent : TThreadSafeLogEvent;
     FThreadSafeLogEvent : TThreadSafeLogEvent;
-    Procedure NotifyNewLog(logtype : TLogType; Const sender, logtext : String);
+    FProcessGlobalLogs: Boolean;
     procedure SetFileName(const Value: AnsiString);
     procedure SetFileName(const Value: AnsiString);
   protected
   protected
     Procedure DoLog(logtype : TLogType; sender, logtext : AnsiString); virtual;
     Procedure DoLog(logtype : TLogType; sender, logtext : AnsiString); virtual;
@@ -64,9 +65,12 @@ type
     Constructor Create(AOwner : TComponent); override;
     Constructor Create(AOwner : TComponent); override;
     Destructor Destroy; override;
     Destructor Destroy; override;
     Class Procedure NewLog(logtype : TLogType; Const sender, logtext : String);
     Class Procedure NewLog(logtype : TLogType; Const sender, logtext : String);
+    Property OnInThreadNewLog : TNewLogEvent read FOnInThreadNewLog write FOnInThreadNewLog;
     Property OnNewLog : TNewLogEvent read FOnNewLog write FOnNewLog;
     Property OnNewLog : TNewLogEvent read FOnNewLog write FOnNewLog;
     Property FileName : AnsiString read FFileName write SetFileName;
     Property FileName : AnsiString read FFileName write SetFileName;
     Property SaveTypes : TLogTypes read FSaveTypes write FSaveTypes;
     Property SaveTypes : TLogTypes read FSaveTypes write FSaveTypes;
+    Property ProcessGlobalLogs : Boolean read FProcessGlobalLogs write FProcessGlobalLogs;
+    Procedure NotifyNewLog(logtype : TLogType; Const sender, logtext : String);
   End;
   End;
 
 
 Const
 Const
@@ -88,11 +92,11 @@ constructor TLog.Create(AOwner: TComponent);
 Var l : TList;
 Var l : TList;
 begin
 begin
   inherited;
   inherited;
-
+  FProcessGlobalLogs := true;
   FLogDataList := TThreadList.Create;
   FLogDataList := TThreadList.Create;
   FFileStream := Nil;
   FFileStream := Nil;
   FFileName := '';
   FFileName := '';
-  FSaveTypes := [ltinfo, ltupdate, lterror];
+  FSaveTypes := CT_TLogTypes_DEFAULT;
   if (Not assigned(_logs)) then _logs := TList.Create;
   if (Not assigned(_logs)) then _logs := TList.Create;
   _logs.Add(self);
   _logs.Add(self);
   FThreadSafeLogEvent := TThreadSafeLogEvent.Create(true);
   FThreadSafeLogEvent := TThreadSafeLogEvent.Create(true);
@@ -135,7 +139,9 @@ var i : Integer;
 begin
 begin
   if (Not Assigned(_logs)) then exit;
   if (Not Assigned(_logs)) then exit;
   for i := 0 to _logs.Count - 1 do begin
   for i := 0 to _logs.Count - 1 do begin
-    TLog(_logs[i]).NotifyNewLog(logtype,sender,logtext);
+    if (TLog(_logs[i]).FProcessGlobalLogs) then begin
+      TLog(_logs[i]).NotifyNewLog(logtype,sender,logtext);
+    end;
   end;
   end;
 end;
 end;
 
 
@@ -149,14 +155,19 @@ begin
     s := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',now)+tid+IntToHex(TThread.CurrentThread.ThreadID,8)+' ['+CT_LogType[logtype]+'] <'+sender+'> '+logtext+#13#10;
     s := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz',now)+tid+IntToHex(TThread.CurrentThread.ThreadID,8)+' ['+CT_LogType[logtype]+'] <'+sender+'> '+logtext+#13#10;
     FFileStream.Write(s[1],length(s));
     FFileStream.Write(s[1],length(s));
   end;
   end;
-  // Add to a thread safe list
-  New(P);
-  P^.Logtype := logtype;
-  P^.Time := now;
-  P^.ThreadID :=TThread.CurrentThread.ThreadID;
-  P^.Sender := sender;
-  P^.Logtext := logtext;
-  FLogDataList.Add(P);
+  if Assigned(FOnInThreadNewLog) then begin
+    FOnInThreadNewLog(logtype,now,TThread.CurrentThread.ThreadID,sender,logtext);
+  end;
+  if Assigned(FOnNewLog) then begin
+    // Add to a thread safe list
+    New(P);
+    P^.Logtype := logtype;
+    P^.Time := now;
+    P^.ThreadID :=TThread.CurrentThread.ThreadID;
+    P^.Sender := sender;
+    P^.Logtext := logtext;
+    FLogDataList.Add(P);
+  end;
   DoLog(logtype,sender,logtext);
   DoLog(logtype,sender,logtext);
 end;
 end;
 
 
@@ -184,7 +195,9 @@ procedure TThreadSafeLogEvent.BCExecute;
 begin
 begin
   while (not Terminated) do begin
   while (not Terminated) do begin
     sleep(100);
     sleep(100);
-    If Not Terminated then Synchronize(SynchronizedProcess);
+    If (Not Terminated) And (Assigned(FLog.OnNewLog)) then begin
+      Synchronize(SynchronizedProcess);
+    end;
   end;
   end;
 end;
 end;
 
 
@@ -202,12 +215,12 @@ begin
   l := FLog.FLogDataList.LockList;
   l := FLog.FLogDataList.LockList;
   try
   try
     try
     try
-      if Assigned(FLog.FOnNewLog) then begin
-        for i := 0 to l.Count - 1 do begin
-          P := PLogData(l[i]);
+      for i := 0 to l.Count - 1 do begin
+        P := PLogData(l[i]);
+        if Assigned(FLog.FOnNewLog) then begin
           FLog.OnNewLog( P^.Logtype,P^.Time,P^.ThreadID,P^.Sender,P^.Logtext );
           FLog.OnNewLog( P^.Logtype,P^.Time,P^.ThreadID,P^.Sender,P^.Logtext );
-          Dispose(P);
         end;
         end;
+        Dispose(P);
       end;
       end;
     finally
     finally
       // Protection for possible raise
       // Protection for possible raise

+ 64 - 34
Units/PascalCoin/UNetProtocol.pas

@@ -184,8 +184,10 @@ Type
     FMaxRemoteOperationBlock : TOperationBlock;
     FMaxRemoteOperationBlock : TOperationBlock;
     FFixedServers : TNodeServerAddressArray;
     FFixedServers : TNodeServerAddressArray;
     FNetClientsDestroyThread : TNetClientsDestroyThread;
     FNetClientsDestroyThread : TNetClientsDestroyThread;
+    FNetConnectionsActive: Boolean;
     Procedure IncStatistics(incActiveConnections,incClientsConnections,incServersConnections,incServersConnectionsWithResponse : Integer; incBytesReceived, incBytesSend : Int64);
     Procedure IncStatistics(incActiveConnections,incClientsConnections,incServersConnections,incServersConnectionsWithResponse : Integer; incBytesReceived, incBytesSend : Int64);
-  protected
+
+    procedure SetNetConnectionsActive(const Value: Boolean);  protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     Function IndexOfNetClient(ListToSearch : TList; ip : AnsiString; port : Word; indexStart : Integer = 0) : Integer;
     Function IndexOfNetClient(ListToSearch : TList; ip : AnsiString; port : Word; indexStart : Integer = 0) : Integer;
     Procedure DeleteNetClient(List : TList; index : Integer);
     Procedure DeleteNetClient(List : TList; index : Integer);
@@ -242,6 +244,7 @@ Type
     Procedure NotifyBlackListUpdated;
     Procedure NotifyBlackListUpdated;
     Procedure NotifyReceivedHelloMessage;
     Procedure NotifyReceivedHelloMessage;
     Procedure NotifyStatisticsChanged;
     Procedure NotifyStatisticsChanged;
+    Property NetConnectionsActive : Boolean read FNetConnectionsActive write SetNetConnectionsActive;
   End;
   End;
 
 
   TNetConnection = Class(TComponent)
   TNetConnection = Class(TComponent)
@@ -385,7 +388,13 @@ begin
   l := FNodeServers.LockList;
   l := FNodeServers.LockList;
   try
   try
     i := IndexOfNetClient(l,NodeServerAddress.ip,NodeServerAddress.port);
     i := IndexOfNetClient(l,NodeServerAddress.ip,NodeServerAddress.port);
-    if i>=0 then exit;
+    if i>=0 then begin
+      P := PNodeServerAddress(l[i]);
+      if NodeServerAddress.last_connection>P^.last_connection then P^.last_connection := NodeServerAddress.last_connection;
+      if NodeServerAddress.last_connection_by_server>P^.last_connection_by_server then P^.last_connection_by_server := NodeServerAddress.last_connection_by_server;
+      if NodeServerAddress.last_attempt_to_connect>P^.last_attempt_to_connect then P^.last_attempt_to_connect := NodeServerAddress.last_attempt_to_connect;
+      exit;
+    end;
     New(P);
     New(P);
     P^ := NodeServerAddress;
     P^ := NodeServerAddress;
     l.Add(P);
     l.Add(P);
@@ -540,6 +549,7 @@ end;
 constructor TNetData.Create;
 constructor TNetData.Create;
 begin
 begin
   TLog.NewLog(ltInfo,ClassName,'TNetData.Create');
   TLog.NewLog(ltInfo,ClassName,'TNetData.Create');
+  FNetConnectionsActive := true;
   SetLength(FFixedServers,0);
   SetLength(FFixedServers,0);
   FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
   FMaxRemoteOperationBlock := CT_OperationBlock_NUL;
   FNetStatistics := CT_TNetStatistics_NUL;
   FNetStatistics := CT_TNetStatistics_NUL;
@@ -696,12 +706,12 @@ Var P : PNodeServerAddress;
   tdc : TThreadDiscoverConnection;
   tdc : TThreadDiscoverConnection;
   canAdd : Boolean;
   canAdd : Boolean;
 begin
 begin
+  if Not FNetConnectionsActive then exit;
   if TPCThread.ThreadClassFound(TThreadDiscoverConnection,nil)>=0 then begin
   if TPCThread.ThreadClassFound(TThreadDiscoverConnection,nil)>=0 then begin
     TLog.NewLog(ltInfo,ClassName,'Allready discovering servers...');
     TLog.NewLog(ltInfo,ClassName,'Allready discovering servers...');
     exit;
     exit;
   end;
   end;
   CleanBlackList;
   CleanBlackList;
-
   j := CT_MaxServersConnected - ConnectionsCount(true);
   j := CT_MaxServersConnected - ConnectionsCount(true);
   if j<=0 then exit;
   if j<=0 then exit;
   // can discover up to j servers
   // can discover up to j servers
@@ -1106,11 +1116,19 @@ begin
   try
   try
     for i := 0 to l.Count - 1 do begin
     for i := 0 to l.Count - 1 do begin
       nsa := PNodeServerAddress( l[i] )^;
       nsa := PNodeServerAddress( l[i] )^;
-      if (Not (nsa.its_myself)) And
-        (nsa.BlackListText='') And
-        (nsa.last_connection>0) And
-        ((Assigned(nsa.netConnection)) Or
-         (nsa.last_connection + (60*60*24) > (currunixtimestamp))) // Only If connected 24h before...
+      If ((nsa.its_myself) Or (nsa.BlackListText='')) // Not a blacklist IP except duplicate connections
+        And
+        ( // I've connected 24h before
+         ((nsa.last_connection>0) And ((Assigned(nsa.netConnection)) Or ((nsa.last_connection + (60*60*24)) > (currunixtimestamp))))
+         Or // Others have connected 24h before
+         ((nsa.last_connection_by_server>0) And ((nsa.last_connection_by_server + (60*60*24)) > (currunixtimestamp)))
+         Or // Peer cache
+         ((nsa.last_connection=0) And (nsa.last_connection_by_server=0))
+        )
+        And
+        ( // Never tried to connect or successfully connected
+          (nsa.total_failed_attemps_to_connect=0)
+        )
         then begin
         then begin
         SetLength(Result,length(Result)+1);
         SetLength(Result,length(Result)+1);
         Result[high(Result)] := nsa;
         Result[high(Result)] := nsa;
@@ -1301,6 +1319,13 @@ begin
   End;
   End;
 end;
 end;
 
 
+procedure TNetData.SetNetConnectionsActive(const Value: Boolean);
+begin
+  FNetConnectionsActive := Value;
+  if FNetConnectionsActive then DiscoverServers
+  else DisconnectClients;
+end;
+
 function TNetData.UnRegisterRequest(Sender: TNetConnection; operation: Word; request_id: Cardinal): Boolean;
 function TNetData.UnRegisterRequest(Sender: TNetConnection; operation: Word; request_id: Cardinal): Boolean;
 Var P : PNetRequestRegistered;
 Var P : PNetRequestRegistered;
   i : Integer;
   i : Integer;
@@ -1337,6 +1362,7 @@ begin
   inherited;
   inherited;
   MaxConnections := CT_MaxClientsConnected;
   MaxConnections := CT_MaxClientsConnected;
   NetTcpIpClientClass := TBufferedNetTcpIpClient;
   NetTcpIpClientClass := TBufferedNetTcpIpClient;
+  Port := CT_NetServer_Port;
 end;
 end;
 
 
 procedure TNetServer.OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient);
 procedure TNetServer.OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient);
@@ -1915,7 +1941,6 @@ procedure TNetConnection.DoProcess_Hello(HeaderData: TNetHeaderData; DataBuffer:
   End;
   End;
 var op, myLastOp : TPCOperationsComp;
 var op, myLastOp : TPCOperationsComp;
     errors : AnsiString;
     errors : AnsiString;
-    messagehello : TNetMessage_Hello;
     connection_has_a_server : Word;
     connection_has_a_server : Word;
     i,c : Integer;
     i,c : Integer;
     nsa : TNodeServerAddress;
     nsa : TNodeServerAddress;
@@ -1925,7 +1950,6 @@ var op, myLastOp : TPCOperationsComp;
    RawAccountKey : TRawBytes;
    RawAccountKey : TRawBytes;
    other_version : AnsiString;
    other_version : AnsiString;
 Begin
 Begin
-  SetLength(messagehello.servers_address,0);
   op := TPCOperationsComp.Create(Nil);
   op := TPCOperationsComp.Create(Nil);
   try
   try
     DataBuffer.Position:=0;
     DataBuffer.Position:=0;
@@ -1963,7 +1987,6 @@ Begin
     end;
     end;
 
 
     if op.LoadBlockFromStream(DataBuffer,errors) then begin
     if op.LoadBlockFromStream(DataBuffer,errors) then begin
-      messagehello.last_operation := op.OperationBlock;
       FRemoteOperationBlock := op.OperationBlock;
       FRemoteOperationBlock := op.OperationBlock;
       If (TNetData.NetData.FMaxRemoteOperationBlock.block<FRemoteOperationBlock.block) then begin
       If (TNetData.NetData.FMaxRemoteOperationBlock.block<FRemoteOperationBlock.block) then begin
         TNetData.NetData.FMaxRemoteOperationBlock := FRemoteOperationBlock;
         TNetData.NetData.FMaxRemoteOperationBlock := FRemoteOperationBlock;
@@ -1977,14 +2000,8 @@ Begin
           nsa := CT_TNodeServerAddress_NUL;
           nsa := CT_TNodeServerAddress_NUL;
           TStreamOp.ReadAnsiString(DataBuffer,nsa.ip);
           TStreamOp.ReadAnsiString(DataBuffer,nsa.ip);
           DataBuffer.Read(nsa.port,2);
           DataBuffer.Read(nsa.port,2);
-          // New in Build 1.0.2 saved at last_connection_by_server DataBuffer.Read(nsa.last_connection,4);
           DataBuffer.Read(nsa.last_connection_by_server,4);
           DataBuffer.Read(nsa.last_connection_by_server,4);
-          if ((nsa.last_connection_by_server + (60*60*24)) > UnivDateTimeToUnix(DateTime2UnivDateTime(now))) then begin
-            // New in Build 1.0.2: Only stores if connected 24 h before
-            SetLength(messagehello.servers_address,length(messagehello.servers_address)+1);
-            messagehello.servers_address[high(messagehello.servers_address)] := nsa;
-            TNetData.NetData.AddServer(nsa);
-          end;
+          TNetData.NetData.AddServer(nsa);
         end;
         end;
         if TStreamOp.ReadAnsiString(DataBuffer,other_version)>=0 then begin
         if TStreamOp.ReadAnsiString(DataBuffer,other_version)>=0 then begin
           // Captures version
           // Captures version
@@ -2217,7 +2234,7 @@ function TNetConnection.ReadTcpClientBuffer(MaxWaitMiliseconds: Cardinal; var He
 var buffer : Array[1..4096] of byte;
 var buffer : Array[1..4096] of byte;
   auxstream : TMemoryStream;
   auxstream : TMemoryStream;
   tc : Cardinal;
   tc : Cardinal;
-  last_bytes_read : Int64;
+  last_bytes_read, t_bytes_read : Int64;
   //
   //
   operation : Word;
   operation : Word;
   request_id : Integer;
   request_id : Integer;
@@ -2226,6 +2243,7 @@ var buffer : Array[1..4096] of byte;
 
 
 
 
 begin
 begin
+  t_bytes_read := 0;
   Result := false;
   Result := false;
   HeaderData := CT_NetHeaderData;
   HeaderData := CT_NetHeaderData;
   BufferData.Size := 0;
   BufferData.Size := 0;
@@ -2283,20 +2301,11 @@ begin
             FClientBufferRead.CopyFrom(auxstream,last_bytes_read);
             FClientBufferRead.CopyFrom(auxstream,last_bytes_read);
             FClientBufferRead.Position := 0;
             FClientBufferRead.Position := 0;
             auxstream.Size := 0;
             auxstream.Size := 0;
+            inc(t_bytes_read,last_bytes_read);
           end;
           end;
         finally
         finally
           (Client as TBufferedNetTcpIpClient).ReadBufferUnlock;
           (Client as TBufferedNetTcpIpClient).ReadBufferUnlock;
         end;
         end;
-        if last_bytes_read>0 then begin
-          if Not FHasReceivedData then begin
-            FHasReceivedData := true;
-            if (Self is TNetClient) then
-              TNetData.NetData.IncStatistics(0,0,0,1,last_bytes_read,0)
-            else TNetData.NetData.IncStatistics(0,0,0,0,last_bytes_read,0);
-          end else begin
-            TNetData.NetData.IncStatistics(0,0,0,0,last_bytes_read,0);
-          end;
-        end;
       end;
       end;
     until (Result) Or ((GetTickCount > (tc+MaxWaitMiliseconds)) And (last_bytes_read=0));
     until (Result) Or ((GetTickCount > (tc+MaxWaitMiliseconds)) And (last_bytes_read=0));
   finally
   finally
@@ -2314,6 +2323,16 @@ begin
       FNetLock.Release;
       FNetLock.Release;
     End;
     End;
   end;
   end;
+  if t_bytes_read>0 then begin
+    if Not FHasReceivedData then begin
+      FHasReceivedData := true;
+      if (Self is TNetClient) then
+        TNetData.NetData.IncStatistics(0,0,0,1,t_bytes_read,0)
+      else TNetData.NetData.IncStatistics(0,0,0,0,t_bytes_read,0);
+    end else begin
+      TNetData.NetData.IncStatistics(0,0,0,0,t_bytes_read,0);
+    end;
+  end;
   if (Result) And (HeaderData.header_type=ntp_response) then begin
   if (Result) And (HeaderData.header_type=ntp_response) then begin
     TNetData.NetData.UnRegisterRequest(Self,HeaderData.operation,HeaderData.request_id);
     TNetData.NetData.UnRegisterRequest(Self,HeaderData.operation,HeaderData.request_id);
   end;
   end;
@@ -2516,10 +2535,7 @@ begin
         data.Write(nsa.last_connection,4);
         data.Write(nsa.last_connection,4);
       end;
       end;
       // Send client version
       // Send client version
-// XXXXXXXXXXXXX
-//      TStreamOp.WriteAnsiString(data,CT_ClientAppVersion{$IFDEF LINUX}+'l'{$ELSE}+'w'{$IFDEF Synapse}+'s'{$ENDIF}{$ENDIF}{$IFDEF OpenSSL10}+'0'{$ELSE}+'1'{$ENDIF});
-      TStreamOp.WriteAnsiString(data,CT_ClientAppVersion{$IFDEF LINUX}+'l'{$ELSE}+'w'{$ENDIF});
-// XXXXXXXXXXXXX
+      TStreamOp.WriteAnsiString(data,CT_ClientAppVersion{$IFDEF LINUX}+'l'{$ELSE}+'w'{$IFDEF Synapse}+'s'{$ENDIF}{$ENDIF}{$IFDEF OpenSSL10}+'0'{$ELSE}+'1'{$ENDIF});
     finally
     finally
       op.free;
       op.free;
     end;
     end;
@@ -2692,7 +2708,7 @@ Var NC : TNetClient;
 begin
 begin
   if Terminated then exit;
   if Terminated then exit;
 
 
-  TLog.NewLog(ltdebug,Classname,'Starting discovery of connection '+FNodeServerAddress.ip+':'+InttoStr(FNodeServerAddress.port));
+  TLog.NewLog(ltInfo,Classname,'Starting discovery of connection '+FNodeServerAddress.ip+':'+InttoStr(FNodeServerAddress.port));
   Pnsa := Nil;
   Pnsa := Nil;
   DebugStep := 'Locking list';
   DebugStep := 'Locking list';
   // Register attempt
   // Register attempt
@@ -2756,6 +2772,7 @@ Var l : TList;
   netserverclientstop : TNetServerClient;
   netserverclientstop : TNetServerClient;
   aux : AnsiString;
   aux : AnsiString;
   needother : Boolean;
   needother : Boolean;
+  newstats : TNetStatistics;
 begin
 begin
   FLastCheckTS := GetTickCount;
   FLastCheckTS := GetTickCount;
   while (Not Terminated) do begin
   while (Not Terminated) do begin
@@ -2770,15 +2787,23 @@ begin
       l := FNetData.FNetConnections.LockList;
       l := FNetData.FNetConnections.LockList;
       try
       try
         ntotal := l.Count;
         ntotal := l.Count;
+        newstats := CT_TNetStatistics_NUL;
         for i := l.Count-1 downto 0 do begin
         for i := l.Count-1 downto 0 do begin
           netconn := TNetConnection(l.Items[i]);
           netconn := TNetConnection(l.Items[i]);
           if (netconn is TNetClient) then begin
           if (netconn is TNetClient) then begin
+            if (netconn.Connected) then begin
+              inc(newstats.ServersConnections);
+              if (netconn.FHasReceivedData) then inc(newstats.ServersConnectionsWithResponse);
+            end;
             if (Not TNetClient(netconn).Connected) And (netconn.CreatedTime+EncodeTime(0,0,5,0)<now) then begin
             if (Not TNetClient(netconn).Connected) And (netconn.CreatedTime+EncodeTime(0,0,5,0)<now) then begin
               // Free this!
               // Free this!
               TNetClient(netconn).FinalizeConnection;
               TNetClient(netconn).FinalizeConnection;
               inc(ndeleted);
               inc(ndeleted);
             end else inc(nactive);
             end else inc(nactive);
           end else if (netconn is TNetServerClient) then begin
           end else if (netconn is TNetServerClient) then begin
+            if (netconn.Connected) then begin
+              inc(newstats.ClientsConnections);
+            end;
             inc(nserverclients);
             inc(nserverclients);
             if (Not netconn.FDoFinalizeConnection) then begin
             if (Not netconn.FDoFinalizeConnection) then begin
               // Build 1.0.9 BUG-101 Only disconnect old versions prior to 1.0.9
               // Build 1.0.9 BUG-101 Only disconnect old versions prior to 1.0.9
@@ -2797,6 +2822,11 @@ begin
             end;
             end;
           end;
           end;
         end;
         end;
+        // Update stats:
+        FNetData.FNetStatistics.ActiveConnections := newstats.ClientsConnections + newstats.ServersConnections;
+        FNetData.FNetStatistics.ClientsConnections := newstats.ClientsConnections;
+        FNetData.FNetStatistics.ServersConnections := newstats.ServersConnections;
+        FNetData.FNetStatistics.ServersConnectionsWithResponse := newstats.ServersConnectionsWithResponse;
         // Must stop clients?
         // Must stop clients?
         if (nserverclients>CT_MaxServersConnected) And // This is to ensure there are more serverclients than clients
         if (nserverclients>CT_MaxServersConnected) And // This is to ensure there are more serverclients than clients
            ((nserverclients + nactive + ndeleted)>=CT_MaxClientsConnected) And (Assigned(netserverclientstop)) then begin
            ((nserverclients + nactive + ndeleted)>=CT_MaxClientsConnected) And (Assigned(netserverclientstop)) then begin

+ 167 - 6
Units/PascalCoin/UNode.pas

@@ -30,11 +30,15 @@ unit UNode;
 interface
 interface
 
 
 uses
 uses
-  Classes, UBlockChain, UNetProtocol, UMiner, UAccounts, UCrypto, UThread, SyncObjs;
+  Classes, UBlockChain, UNetProtocol, UMiner, UAccounts, UCrypto, UThread, SyncObjs, ULog;
 
 
 Type
 Type
+
+  { TNode }
+
   TNode = Class(TComponent)
   TNode = Class(TComponent)
   private
   private
+    FNodeLog : TLog;
     FLockNodeOperations : TCriticalSection;
     FLockNodeOperations : TCriticalSection;
     FNotifyList : TList;
     FNotifyList : TList;
     FBank : TPCBank;
     FBank : TPCBank;
@@ -47,6 +51,8 @@ Type
     Procedure OnBankNewBlock(Sender : TObject);
     Procedure OnBankNewBlock(Sender : TObject);
     Procedure OnMinerThreadTerminate(Sender : TObject);
     Procedure OnMinerThreadTerminate(Sender : TObject);
     Procedure OnMinerNewBlockFound(sender : TMinerThread; Operations : TPCOperationsComp; Var Correct : Boolean);
     Procedure OnMinerNewBlockFound(sender : TMinerThread; Operations : TPCOperationsComp; Var Correct : Boolean);
+    procedure SetNodeLogFilename(const Value: AnsiString);
+    function GetNodeLogFilename: AnsiString;
   protected
   protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
   public
   public
@@ -72,12 +78,16 @@ Type
     //
     //
     Procedure NotifyBlocksChanged;
     Procedure NotifyBlocksChanged;
     //
     //
+    procedure GetStoredOperationsFromAccount(const OperationsResume: TOperationsResumeList; account_number: Cardinal; MaxDeep : Integer);
+    Function FindOperation(Const OperationComp : TPCOperationsComp; Const OperationHash : TRawBytes; var block : Cardinal; var operation_block_index : Integer) : Boolean;
+    //
     Procedure AutoDiscoverNodes(Const ips : AnsiString);
     Procedure AutoDiscoverNodes(Const ips : AnsiString);
     Function IsBlockChainValid(var WhyNot : AnsiString) : Boolean;
     Function IsBlockChainValid(var WhyNot : AnsiString) : Boolean;
     Function IsReady(Var CurrentProcess : AnsiString) : Boolean;
     Function IsReady(Var CurrentProcess : AnsiString) : Boolean;
     Property PeerCache : AnsiString read FPeerCache write FPeerCache;
     Property PeerCache : AnsiString read FPeerCache write FPeerCache;
     Procedure DisableNewBlocks;
     Procedure DisableNewBlocks;
     Procedure EnableNewBlocks;
     Procedure EnableNewBlocks;
+    Property NodeLogFilename : AnsiString read GetNodeLogFilename write SetNodeLogFilename;
   End;
   End;
 
 
   TNodeNotifyEvents = Class;
   TNodeNotifyEvents = Class;
@@ -134,7 +144,7 @@ Type
 
 
 implementation
 implementation
 
 
-Uses UOpTransaction, SysUtils, ULog, UConst, UTime;
+Uses UOpTransaction, SysUtils,  UConst, UTime;
 
 
 var _Node : TNode;
 var _Node : TNode;
 
 
@@ -185,6 +195,13 @@ begin
     try
     try
       FOperations.SaveBlockToStream(false,ms);
       FOperations.SaveBlockToStream(false,ms);
       Result := Bank.AddNewBlockChainBlock(NewBlockOperations,newBlockAccount,errors);
       Result := Bank.AddNewBlockChainBlock(NewBlockOperations,newBlockAccount,errors);
+      if Result then begin
+        if Assigned(SenderConnection) then begin
+          FNodeLog.NotifyNewLog(ltupdate,SenderConnection.ClassName,Format(';%d;%s;%s',[NewBlockOperations.OperationBlock.block,SenderConnection.ClientRemoteAddr,NewBlockOperations.OperationBlock.block_payload]));
+        end else begin
+          FNodeLog.NotifyNewLog(ltupdate,ClassName,Format(';%d;%s;%s',[NewBlockOperations.OperationBlock.block,'NIL',NewBlockOperations.OperationBlock.block_payload]));
+        end;
+      end;
       FOperations.Clear(true);
       FOperations.Clear(true);
       ms.Position:=0;
       ms.Position:=0;
       If Not FOperations.LoadBlockFromStream(ms,errors2) then begin
       If Not FOperations.LoadBlockFromStream(ms,errors2) then begin
@@ -362,7 +379,7 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TNode.AutoDiscoverNodes(Const ips : AnsiString);
+procedure TNode.AutoDiscoverNodes(const ips: AnsiString);
 Var i,j : Integer;
 Var i,j : Integer;
   nsarr : TNodeServerAddressArray;
   nsarr : TNodeServerAddressArray;
 begin
 begin
@@ -377,6 +394,8 @@ end;
 
 
 constructor TNode.Create(AOwner: TComponent);
 constructor TNode.Create(AOwner: TComponent);
 begin
 begin
+  FNodeLog := TLog.Create(Self);
+  FNodeLog.ProcessGlobalLogs := false;
   RegisterOperationsClass;
   RegisterOperationsClass;
   if Assigned(_Node) then raise Exception.Create('Duplicate nodes protection');
   if Assigned(_Node) then raise Exception.Create('Duplicate nodes protection');
   TLog.NewLog(ltInfo,ClassName,'TNode.Create');
   TLog.NewLog(ltInfo,ClassName,'TNode.Create');
@@ -395,8 +414,8 @@ begin
   if Not Assigned(_Node) then _Node := Self;
   if Not Assigned(_Node) then _Node := Self;
 end;
 end;
 
 
-class procedure TNode.DecodeIpStringToNodeServerAddressArray(Const Ips: AnsiString;
-  var NodeServerAddressArray: TNodeServerAddressArray);
+class procedure TNode.DecodeIpStringToNodeServerAddressArray(
+  const Ips: AnsiString; var NodeServerAddressArray: TNodeServerAddressArray);
   Function GetIp(var ips_string : AnsiString; var nsa : TNodeServerAddress) : Boolean;
   Function GetIp(var ips_string : AnsiString; var nsa : TNodeServerAddress) : Boolean;
   Const CT_IP_CHARS = ['a'..'z','A'..'Z','0'..'9','.','-','_'];
   Const CT_IP_CHARS = ['a'..'z','A'..'Z','0'..'9','.','-','_'];
   var i : Integer;
   var i : Integer;
@@ -491,6 +510,7 @@ begin
     FreeAndNil(FBank);
     FreeAndNil(FBank);
 
 
     step := 'inherited';
     step := 'inherited';
+    FreeAndNil(FNodeLog);
     inherited;
     inherited;
   Except
   Except
     On E:Exception do begin
     On E:Exception do begin
@@ -526,6 +546,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TNode.GetNodeLogFilename: AnsiString;
+begin
+  Result := FNodeLog.FileName;
+end;
+
 function TNode.IsBlockChainValid(var WhyNot : AnsiString): Boolean;
 function TNode.IsBlockChainValid(var WhyNot : AnsiString): Boolean;
 Var unixtimediff : Integer;
 Var unixtimediff : Integer;
 begin
 begin
@@ -606,6 +631,136 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TNode.GetStoredOperationsFromAccount(const OperationsResume: TOperationsResumeList; account_number: Cardinal; MaxDeep: Integer);
+  Procedure DoGetFromBlock(block_number : Cardinal; last_balance : Int64; act_deep : Integer);
+  var opc : TPCOperationsComp;
+    op : TPCOperation;
+    OPR : TOperationResume;
+    l : TList;
+    i : Integer;
+    next_block_number : Cardinal;
+  begin
+    if (act_deep<=0) Or ((block_number<=0) And (block_number>0)) then exit;
+
+    opc := TPCOperationsComp.Create(Nil);
+    Try
+      If not Bank.Storage.LoadBlockChainBlock(opc,block_number) then begin
+        TLog.NewLog(lterror,ClassName,'Error searching for block '+inttostr(block_number));
+        exit;
+      end;
+      l := TList.Create;
+      try
+        next_block_number := 0;
+        opc.OperationsHashTree.GetOperationsAffectingAccount(account_number,l);
+        for i := l.Count - 1 downto 0 do begin
+          op := opc.Operation[PtrInt(l.Items[i])];
+          if (i=0) then begin
+            If op.SenderAccount=account_number then next_block_number := op.Previous_Sender_updated_block
+            else next_block_number := op.Previous_Destination_updated_block;
+          end;
+          If TPCOperation.OperationToOperationResume(block_number,Op,account_number,OPR) then begin
+            OPR.NOpInsideBlock := i;
+            OPR.time := opc.OperationBlock.timestamp;
+            OPR.Block := block_number;
+            OPR.Balance := last_balance;
+            last_balance := last_balance - ( OPR.Amount + OPR.Fee );
+            OperationsResume.Add(OPR);
+          end;
+        end;
+        // Is a new block operation?
+        if (TAccountComp.AccountBlock(account_number)=block_number) And ((account_number MOD CT_AccountsPerBlock)=0) then begin
+          OPR := CT_TOperationResume_NUL;
+          OPR.Block := block_number;
+          OPR.time := opc.OperationBlock.timestamp;
+          OPR.AffectedAccount := account_number;
+          OPR.Amount := opc.OperationBlock.reward;
+          OPR.Fee := opc.OperationBlock.fee;
+          OPR.Balance := last_balance;
+          OPR.OperationTxt := 'Blockchain reward';
+          OperationsResume.Add(OPR);
+        end;
+        //
+        opc.Clear(true);
+        if (next_block_number>=0) And (next_block_number<block_number) And (act_deep>0)
+           And (next_block_number >= (account_number DIV CT_AccountsPerBlock)) then DoGetFromBlock(next_block_number,last_balance,act_deep-1);
+      finally
+        l.Free;
+      end;
+    Finally
+      opc.Free;
+    End;
+  end;
+
+Var acc : TAccount;
+begin
+  if MaxDeep<0 then exit;
+  if account_number>=Bank.SafeBox.AccountsCount then exit;
+  acc := Bank.SafeBox.Account(account_number);
+  if (acc.updated_block>0) Or (acc.account=0) then DoGetFromBlock(acc.updated_block,acc.balance,MaxDeep);
+end;
+
+function TNode.FindOperation(const OperationComp: TPCOperationsComp;
+  const OperationHash: TRawBytes; var block: Cardinal;
+  var operation_block_index: Integer): Boolean;
+  { With a OperationHash, search it }
+var account,n_operation : Cardinal;
+  i : Integer;
+  op : TPCOperation;
+  initial_block, aux_block : Cardinal;
+begin
+  Result := False;
+  // Decode OperationHash
+  If not TPCOperation.DecodeOperationHash(OperationHash,block,account,n_operation) then exit;
+  initial_block := block;
+  //
+  If (account>=Bank.AccountsCount) then exit; // Invalid account number
+  // If block=0 then we must search in pending operations first
+  if (block=0) then begin
+    FOperations.Lock;
+    Try
+      For i:=0 to FOperations.Count-1 do begin
+        If (FOperations.Operation[i].SenderAccount=account) then begin
+          If (TPCOperation.OperationHash(FOperations.Operation[i],0)=OperationHash) then begin
+            operation_block_index:=i;
+            OperationComp.CopyFrom(FOperations);
+            Result := true;
+            exit;
+          end;
+        end;
+      end;
+    finally
+      FOperations.Unlock;
+    end;
+    // block=0 and not found... start searching at block updated by account updated_block
+    block := Bank.SafeBox.Account(account).updated_block;
+    if Bank.SafeBox.Account(account).n_operation<n_operation then exit; // n_operation is greater than found in safebox
+  end;
+  if (block=0) or (block>=Bank.BlocksCount) then exit;
+  // Search in previous blocks
+  While (Not Result) And (block>0) do begin
+    aux_block := block;
+    If Not Bank.LoadOperations(OperationComp,block) then exit;
+    For i:=OperationComp.Count-1 downto 0 do begin
+      op := OperationComp.Operation[i];
+      if (op.SenderAccount=account) then begin
+        If (op.N_Operation<n_operation) then exit; // n_operation is greaten than found
+        If (op.N_Operation=n_operation) then begin
+          // Possible candidate or dead
+          If TPCOperation.OperationHash(op,initial_block)=OperationHash then begin
+            operation_block_index:=i;
+            Result := true;
+            exit;
+          end else exit; // Not found!
+        end;
+        If op.Previous_Sender_updated_block>block then exit;
+        block := op.Previous_Sender_updated_block;
+      end;
+    end;
+    if (block>=aux_block) then exit; // Error... not found a valid block positioning
+    if (initial_block<>0) then exit; // If not found in specified block, no valid hash
+  end;
+end;
+
 procedure TNode.NotifyNetClientMessage(Sender: TNetConnection; const TheMessage: AnsiString);
 procedure TNode.NotifyNetClientMessage(Sender: TNetConnection; const TheMessage: AnsiString);
 Var i : Integer;
 Var i : Integer;
   s : AnsiString;
   s : AnsiString;
@@ -622,7 +777,8 @@ begin
   FOperations.SanitizeOperations;
   FOperations.SanitizeOperations;
 end;
 end;
 
 
-procedure TNode.OnMinerNewBlockFound(sender: TMinerThread; Operations: TPCOperationsComp; Var Correct : Boolean);
+procedure TNode.OnMinerNewBlockFound(sender: TMinerThread;
+  Operations: TPCOperationsComp; var Correct: Boolean);
 Var nba : TBlockAccount;
 Var nba : TBlockAccount;
   errors : AnsiString;
   errors : AnsiString;
 begin
 begin
@@ -671,6 +827,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TNode.SetNodeLogFilename(const Value: AnsiString);
+begin
+  FNodeLog.FileName := Value;
+end;
+
 { TNodeNotifyEvents }
 { TNodeNotifyEvents }
 
 
 constructor TNodeNotifyEvents.Create(AOwner: TComponent);
 constructor TNodeNotifyEvents.Create(AOwner: TComponent);

+ 30 - 0
Units/PascalCoin/UOpTransaction.pas

@@ -50,6 +50,8 @@ Type
     fee: UInt64;
     fee: UInt64;
   End;
   End;
 
 
+  { TOpTransaction }
+
   TOpTransaction = Class(TPCOperation)
   TOpTransaction = Class(TPCOperation)
   private
   private
     FData : TOpTransactionData;
     FData : TOpTransactionData;
@@ -67,12 +69,15 @@ Type
     function OperationFee : UInt64; override;
     function OperationFee : UInt64; override;
     function OperationPayload : TRawBytes; override;
     function OperationPayload : TRawBytes; override;
     function SenderAccount : Cardinal; override;
     function SenderAccount : Cardinal; override;
+    function N_Operation : Cardinal; override;
     Property Data : TOpTransactionData read FData;
     Property Data : TOpTransactionData read FData;
 
 
     Constructor Create(sender, n_operation, target: Cardinal; key: TECPrivateKey; amount, fee: UInt64; payload: AnsiString);
     Constructor Create(sender, n_operation, target: Cardinal; key: TECPrivateKey; amount, fee: UInt64; payload: AnsiString);
     Function toString : String; Override;
     Function toString : String; Override;
   End;
   End;
 
 
+  { TOpChangeKey }
+
   TOpChangeKey = Class(TPCOperation)
   TOpChangeKey = Class(TPCOperation)
   private
   private
     FData : TOpChangeKeyData;
     FData : TOpChangeKeyData;
@@ -89,12 +94,15 @@ Type
     function OperationFee : UInt64; override;
     function OperationFee : UInt64; override;
     function OperationPayload : TRawBytes; override;
     function OperationPayload : TRawBytes; override;
     function SenderAccount : Cardinal; override;
     function SenderAccount : Cardinal; override;
+    function N_Operation : Cardinal; override;
     procedure AffectedAccounts(list : TList); override;
     procedure AffectedAccounts(list : TList); override;
     Constructor Create(account_number, n_operation: Cardinal; key:TECPrivateKey; new_account_key : TAccountKey; fee: UInt64; payload: AnsiString);
     Constructor Create(account_number, n_operation: Cardinal; key:TECPrivateKey; new_account_key : TAccountKey; fee: UInt64; payload: AnsiString);
     Property Data : TOpChangeKeyData read FData;
     Property Data : TOpChangeKeyData read FData;
     Function toString : String; Override;
     Function toString : String; Override;
   End;
   End;
 
 
+  { TOpRecoverFounds }
+
   TOpRecoverFounds = Class(TPCOperation)
   TOpRecoverFounds = Class(TPCOperation)
   private
   private
     FData : TOpRecoverFoundsData;
     FData : TOpRecoverFoundsData;
@@ -109,6 +117,7 @@ Type
     function OperationFee : UInt64; override;
     function OperationFee : UInt64; override;
     function OperationPayload : TRawBytes; override;
     function OperationPayload : TRawBytes; override;
     function SenderAccount : Cardinal; override;
     function SenderAccount : Cardinal; override;
+    function N_Operation : Cardinal; override;
     procedure AffectedAccounts(list : TList); override;
     procedure AffectedAccounts(list : TList); override;
     Constructor Create(account_number, n_operation: Cardinal; fee: UInt64);
     Constructor Create(account_number, n_operation: Cardinal; fee: UInt64);
     Property Data : TOpRecoverFoundsData read FData;
     Property Data : TOpRecoverFoundsData read FData;
@@ -225,6 +234,12 @@ class function TOpTransaction.DoSignOperation(key : TECPrivateKey; var trans : T
 var s : AnsiString;
 var s : AnsiString;
   _sign : TECDSA_SIG;
   _sign : TECDSA_SIG;
 begin
 begin
+  If Not Assigned(key.PrivateKey) then begin
+    Result := false;
+    trans.sign.r:='';
+    trans.sign.s:='';
+    exit;
+  end;
   s := GetTransactionHasthToSign(trans);
   s := GetTransactionHasthToSign(trans);
   Try
   Try
     _sign := TCrypto.ECDSASign(key.PrivateKey,s);
     _sign := TCrypto.ECDSASign(key.PrivateKey,s);
@@ -344,6 +359,11 @@ begin
   Result := FData.sender;
   Result := FData.sender;
 end;
 end;
 
 
+function TOpTransaction.N_Operation: Cardinal;
+begin
+  Result := FData.n_operation;
+end;
+
 function TOpTransaction.toString: String;
 function TOpTransaction.toString: String;
 begin
 begin
   Result := Format('Transaction from %s to %s amount:%s fee:%s (n_op:%d) payload size:%d',[
   Result := Format('Transaction from %s to %s amount:%s fee:%s (n_op:%d) payload size:%d',[
@@ -536,6 +556,11 @@ begin
   Result := FData.account;
   Result := FData.account;
 end;
 end;
 
 
+function TOpChangeKey.N_Operation: Cardinal;
+begin
+  Result := FData.n_operation;
+end;
+
 function TOpChangeKey.toString: String;
 function TOpChangeKey.toString: String;
 begin
 begin
   Result := Format('Change key of %s to new key: %s fee:%s (n_op:%d) payload size:%d',[
   Result := Format('Change key of %s to new key: %s fee:%s (n_op:%d) payload size:%d',[
@@ -651,6 +676,11 @@ begin
   Result := FData.account;
   Result := FData.account;
 end;
 end;
 
 
+function TOpRecoverFounds.N_Operation: Cardinal;
+begin
+  Result := FData.n_operation;
+end;
+
 function TOpRecoverFounds.toString: String;
 function TOpRecoverFounds.toString: String;
 begin
 begin
   Result := Format('Recover founds of account %s fee:%s (n_op:%d)',[
   Result := Format('Recover founds of account %s fee:%s (n_op:%d)',[

+ 4 - 0
Units/PascalCoin/UOpenSSL.pas

@@ -20,6 +20,10 @@ unit UOpenSSL;
 
 
 interface
 interface
 
 
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
 Uses UOpenSSLdef;
 Uses UOpenSSLdef;
 {$I config.inc}
 {$I config.inc}
 
 

+ 4 - 0
Units/PascalCoin/UOpenSSLdef.pas

@@ -20,6 +20,10 @@ unit UOpenSSLdef;
 
 
 interface
 interface
 
 
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
 uses {$IFDEF UNIX}BaseUnix {$ELSE} Windows{$ENDIF};
 uses {$IFDEF UNIX}BaseUnix {$ELSE} Windows{$ENDIF};
 
 
 {$REGION 'OBJECT'}
 {$REGION 'OBJECT'}

+ 7 - 4
Units/PascalCoin/UPoolMining.pas

@@ -23,7 +23,7 @@ Uses
 {$IFnDEF FPC}
 {$IFnDEF FPC}
   Windows,
   Windows,
 {$ELSE}
 {$ELSE}
-  LCLIntf, LCLType, LMessages,
+  {LCLIntf, LCLType, LMessages,}
 {$ENDIF}
 {$ENDIF}
   UTCPIP, SysUtils, UThread, SyncObjs, Classes, UJSONFunctions, UAES, UNode,
   UTCPIP, SysUtils, UThread, SyncObjs, Classes, UJSONFunctions, UAES, UNode,
   UCrypto, UAccounts;
   UCrypto, UAccounts;
@@ -434,8 +434,8 @@ begin
       end;
       end;
     end;
     end;
     nbOperations.BlockPayload := payload;
     nbOperations.BlockPayload := payload;
-    nbOperations.timestamp := params.AsInteger('timestamp',0);
-    nbOperations.nonce := params.AsInteger('nonce',0);
+    nbOperations.timestamp := params.AsCardinal('timestamp',0);
+    nbOperations.nonce := params.AsCardinal('nonce',0);
     p1 := nbOperations.PoW_Digest_Part1;
     p1 := nbOperations.PoW_Digest_Part1;
     p2 := nbOperations.PoW_Digest_Part2_Payload;
     p2 := nbOperations.PoW_Digest_Part2_Payload;
     p3 := nbOperations.PoW_Digest_Part3;
     p3 := nbOperations.PoW_Digest_Part3;
@@ -445,13 +445,16 @@ begin
       try
       try
         json.GetAsVariant('block').Value := FNodeNotifyEvents.Node.Bank.LastOperationBlock.block;
         json.GetAsVariant('block').Value := FNodeNotifyEvents.Node.Bank.LastOperationBlock.block;
         json.GetAsVariant('pow').Value := TCrypto.ToHexaString( FNodeNotifyEvents.Node.Bank.LastOperationBlock.proof_of_work );
         json.GetAsVariant('pow').Value := TCrypto.ToHexaString( FNodeNotifyEvents.Node.Bank.LastOperationBlock.proof_of_work );
+        json.GetAsVariant('payload').Value := nbOperations.BlockPayload;
+        json.GetAsVariant('timestamp').Value := nbOperations.timestamp;
+        json.GetAsVariant('nonce').Value := nbOperations.nonce;
         inc(FClientsWins);
         inc(FClientsWins);
         Client.SendJSONRPCResponse(json,id);
         Client.SendJSONRPCResponse(json,id);
       finally
       finally
         json.Free;
         json.Free;
       end;
       end;
     end else begin
     end else begin
-      Client.SendJSONRPCErrorResponse(id,'Error: '+errors);
+      Client.SendJSONRPCErrorResponse(id,'Error: '+errors+' payload:'+nbOperations.BlockPayload+' timestamp:'+InttoStr(nbOperations.timestamp)+' nonce:'+IntToStr(nbOperations.nonce));
     end;
     end;
   finally
   finally
     nbOperations.Free;
     nbOperations.Free;

+ 1128 - 7
Units/PascalCoin/URPC.pas

@@ -4,19 +4,1140 @@ unit URPC;
   {$MODE Delphi}
   {$MODE Delphi}
 {$ENDIF}
 {$ENDIF}
 
 
+{ Copyright (c) 2016 by Albert Molina
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  This unit is a part of Pascal Coin, a P2P crypto currency without need of
+  historical operations.
+
+  If you like it, consider a donation using BitCoin:
+  16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
+
+  }
+
 interface
 interface
 
 
-Uses UTCPIP;
+Uses UThread, ULog, UConst, UNode, UAccounts, UCrypto, UBlockChain,
+  UNetProtocol, UOpTransaction, UWalletKeys, UTime, UAES, UECIES,
+  UJSONFunctions, classes, blcksock, synsock, IniFiles;
+
+Const
+  CT_RPC_ErrNum_InternalError = 100;
+
+  CT_RPC_ErrNum_MethodNotFound = 1001;
+  CT_RPC_ErrNum_InvalidAccount = 1002;
+  CT_RPC_ErrNum_InvalidBlock = 1003;
+  CT_RPC_ErrNum_InvalidOperation = 1004;
+  CT_RPC_ErrNum_InvalidPubKey = 1005;
+  CT_RPC_ErrNum_NotFound = 1010;
+  CT_RPC_ErrNum_WalletPasswordProtected = 1015;
+  CT_RPC_ErrNum_InvalidData = 1016;
+
+Type
+
+  { TRPCServer }
+
+  TRPCServerThread = Class;
+  TRPCServer = Class
+  private
+    FRPCServerThread : TRPCServerThread;
+    FActive: Boolean;
+    FWalletKeys: TWalletKeysExt;
+    FPort: Word;
+    FJSON20Strict: Boolean;
+    FIniFileName: AnsiString;
+    FIniFile : TIniFile;
+    procedure SetActive(AValue: Boolean);
+    procedure SetIniFileName(const Value: AnsiString);
+  public
+    Constructor Create;
+    Destructor Destroy; override;
+    Property Port : Word read FPort Write FPort;
+    Property Active : Boolean read FActive write SetActive;
+    Property WalletKeys : TWalletKeysExt read FWalletKeys write FWalletKeys;
+    //
+    Property JSON20Strict : Boolean read FJSON20Strict write FJSON20Strict;
+    Property IniFileName : AnsiString read FIniFileName write SetIniFileName;
+  end;
+
+  { TRPCServerThread }
 
 
-{Type
-  {TRPCServer = Class(TNetTcpIpServer)
+  TRPCServerThread = Class(TPCThread)
+    FServerSocket:TTCPBlockSocket;
+    FPort : Word;
   protected
   protected
-    Procedure OnNewIncommingConnection(Sender : TObject; Client : TNetTcpIpClient); override;
-    procedure SetActive(const Value: Boolean); override;
+    procedure BCExecute; override;
+  public
+    Constructor Create(Port : Word);
+    Destructor Destroy; Override;
+  End;
+
+  { TRPCProcess }
+
+  TRPCProcess = class(TPCThread)
+  private
+    FSock:TTCPBlockSocket;
   public
   public
-    Constructor Create; override;
-  End;}
+    Constructor Create (hsock:tSocket);
+    Destructor Destroy; override;
+    procedure BCExecute; override;
+    function ProcessMethod(Const method : String; params : TPCJSONObject; jsonresponse : TPCJSONObject; Var ErrorNum : Integer; Var ErrorDesc : String) : Boolean;
+  end;
+
 
 
 implementation
 implementation
 
 
+Uses SysUtils, Synautil;
+
+var _RPCServer : TRPCServer = Nil;
+
+{ TRPCServer }
+
+procedure TRPCServer.SetActive(AValue: Boolean);
+begin
+  if FActive=AValue then Exit;
+  FActive:=AValue;
+  if (FActive) then begin
+    FRPCServerThread := TRPCServerThread.Create(FPort);
+  end else begin
+    FRPCServerThread.Terminate;
+    FRPCServerThread.WaitFor;
+    FreeAndNil(FRPCServerThread);
+  end;
+end;
+
+procedure TRPCServer.SetIniFileName(const Value: AnsiString);
+begin
+  if FIniFileName=Value then exit;
+  FreeAndNil(FIniFile);
+  FIniFileName := Value;
+  if (FIniFileName<>'') And (FileExists(FIniFileName)) then begin
+    FIniFile := TIniFile.Create(FIniFileName);
+  end;
+  if Assigned(FIniFile) then begin
+    FJSON20Strict := FIniFile.ReadBool('general','json20strict',true)
+    // TODO
+  end;
+end;
+
+constructor TRPCServer.Create;
+begin
+  FIniFile := Nil;
+  FIniFileName := '';
+  FJSON20Strict := true;
+  FWalletKeys := Nil;
+  FRPCServerThread := Nil;
+  FPort := CT_JSONRPC_Port;
+  If Not assigned(_RPCServer) then _RPCServer := Self;
+end;
+
+destructor TRPCServer.Destroy;
+begin
+  active := false;
+  if _RPCServer=Self then _RPCServer:=Nil;
+  inherited Destroy;
+end;
+
+{ TRPCProcess }
+
+constructor TRPCProcess.Create(hsock: tSocket);
+begin
+  FSock:=TTCPBlockSocket.create;
+  FSock.socket:=HSock;
+  FreeOnTerminate:=true;
+  //Priority:=tpNormal;
+  inherited create(false);
+end;
+
+destructor TRPCProcess.Destroy;
+begin
+  FSock.free;
+  inherited Destroy;
+end;
+
+procedure TRPCProcess.BCExecute;
+var
+  timeout: integer;
+  s: string;
+  method, uri, protocol: string;
+  size: integer;
+  x, n: integer;
+  resultcode: integer;
+  inputdata : TBytes;
+  js,jsresult : TPCJSONData;
+  jsonobj,jsonresponse : TPCJSONObject;
+  errNum : Integer; errDesc : String;
+  jsonrequesttxt,
+  jsonresponsetxt : AnsiString;
+  valid : Boolean;
+  i : Integer;
+  Headers : TStringList;
+begin
+  Headers := TStringList.Create;
+  errNum := CT_RPC_ErrNum_InternalError;
+  errDesc := 'No data';
+  valid := false;
+  SetLength(inputdata,0);
+  jsonresponse := TPCJSONObject.Create;
+  try
+    timeout := 5000;
+    resultcode:= 200;
+    repeat
+      //read request line
+      s := Fsock.RecvString(timeout);
+      if Fsock.lasterror <> 0 then Exit;
+      if s = '' then Exit;
+      method := fetch(s, ' ');
+      if (s = '') or (method = '') then  Exit;
+      uri := fetch(s, ' '); if uri = '' then  Exit;
+      protocol := fetch(s, ' ');
+      headers.Clear;
+      size := -1;
+      //read request headers
+      if protocol <> '' then begin
+        if pos('HTTP/1.1', protocol) <> 1 then begin
+          errDesc := 'Invalid protocol '+protocol;
+          Exit;
+        end;
+        repeat
+          s := Fsock.RecvString(Timeout);
+          if Fsock.lasterror <> 0 then
+            Exit;
+          if Pos('CONTENT-LENGTH:', Uppercase(s)) = 1 then
+            Size := StrToIntDef(SeparateRight(s, ' '), -1);
+        until s = '';
+      end;
+      //recv document...
+      if size >= 0 then begin
+        setLength(inputdata,size);
+        x := FSock.RecvBufferEx(InputData, Size, Timeout);
+        if Fsock.lasterror <> 0 then
+          Exit;
+        if (x<>size) And (x>0) then
+          setLength(inputdata,x);
+      end else setlength(inputdata,0);
+      SetLength(jsonrequesttxt,length(inputdata));
+      for i:=0 to high(inputdata) do begin
+        jsonrequesttxt[i+1] := AnsiChar(inputdata[i]);
+      end;
+      // Convert InputData to JSON object
+      try
+        js := TPCJSONData.ParseJSONValue(jsonrequesttxt);
+      except
+        On E:Exception do begin
+          errDesc:='Error decoding JSON: '+E.Message;
+          TLog.NewLog(lterror,Classname,'Error decoding JSON: '+E.Message);
+          exit;
+        end;
+      end;
+      If Assigned(js) then begin
+        try
+          If (js is TPCJSONObject) then begin
+            jsonobj := TPCJSONObject(js);
+            errNum := 0;
+            errDesc := '';
+            try
+              TLog.NewLog(ltinfo,Classname,'Processing method '+jsonobj.AsString('method',''));
+              Valid := ProcessMethod(jsonobj.AsString('method',''),jsonobj.GetAsObject('params'),jsonresponse,errNum,errDesc);
+              if not Valid then begin
+                if (errNum<>0) or (errDesc<>'') then begin
+                  jsonresponse.GetAsObject('error').GetAsVariant('code').Value:=errNum;
+                  jsonresponse.GetAsObject('error').GetAsVariant('message').Value:=errDesc;
+                end else begin
+                  jsonresponse.GetAsObject('error').GetAsVariant('code').Value:=CT_RPC_ErrNum_InternalError;
+                  jsonresponse.GetAsObject('error').GetAsVariant('message').Value:='Unknown error processing method';
+                end;
+              end;
+            Except
+              on E:Exception do begin
+                TLog.NewLog(lterror,Classname,'Exception processing method'+jsonobj.AsString('method','')+' ('+E.ClassName+'): '+E.Message);
+                jsonresponse.GetAsObject('error').GetAsVariant('code').Value:=CT_RPC_ErrNum_InternalError;
+                jsonresponse.GetAsObject('error').GetAsVariant('message').Value:=E.Message;
+                valid:=False;
+              end;
+            end;
+            jsonresponse.GetAsVariant('id').Value:= jsonobj.GetAsVariant('id').Value;
+            jsonresponse.GetAsVariant('jsonrpc').Value:= '2.0';
+          end;
+        finally
+          js.free;
+        end;
+      end else begin
+        TLog.NewLog(lterror,ClassName,'Received data is not a JSON: '+jsonrequesttxt+' (length '+inttostr(length(jsonrequesttxt))+' bytes)');
+      end;
+    until (FSock.LastError <> 0) Or (protocol<>'');
+  Finally
+    try
+      // Send result:
+      if Fsock.lasterror = 0 then begin
+        // Save JSON response:
+        If (Not Valid) then begin
+          if Not assigned(jsonresponse.FindName('error')) then begin
+            jsonresponse.GetAsObject('error').GetAsVariant('code').Value:=errNum;
+            jsonresponse.GetAsObject('error').GetAsVariant('message').Value:=errDesc;
+          end;
+        end;
+        jsonresponsetxt := jsonresponse.ToJSON(false);
+        Fsock.SendString(protocol + ' ' + IntTostr(ResultCode) + CRLF);
+        if (protocol <> '') then begin
+          headers.Add('Server: PascalCoin HTTP JSON-RPC Server');
+          headers.Add('Content-Type: application/json;charset=utf-8');
+          headers.Add('Content-length: ' + IntTostr(length(jsonresponsetxt)));
+          headers.Add('Connection: close');
+          headers.Add('Access-Control-Allow-Origin: *');
+          headers.Add('Date: ' + Rfc822DateTime(now));
+          headers.Add('');
+          for n := 0 to headers.count - 1 do
+            Fsock.sendstring(headers[n] + CRLF);
+        end;
+        if Fsock.lasterror = 0 then begin
+          FSock.SendBuffer(addr(jsonresponsetxt[1]),Length(jsonresponsetxt));
+        end;
+      end;
+    finally
+      jsonresponse.free;
+    end;
+  end;
+end;
+
+function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
+  jsonresponse: TPCJSONObject; var ErrorNum: Integer; var ErrorDesc: String): Boolean;
+  var _ro : TPCJSONObject;
+      _ra : TPCJSONArray;
+  Function GetResultObject : TPCJSONObject;
+  begin
+    if not assigned(_ro) then begin
+      _ro := jsonresponse.GetAsObject('result');
+      _ra := Nil;
+    end;
+    Result := _ro;
+  end;
+
+  Function GetResultArray : TPCJSONArray;
+  begin
+    if not assigned(_ro) then begin
+      _ra := jsonresponse.GetAsArray('result');
+      _ro := Nil;
+    end;
+    Result := _ra;
+  end;
+
+  Function ToJSONCurrency(pascalCoins : Int64) : Real;
+  Begin
+    Result := pascalCoins / 10000;
+  End;
+
+  Function ToPascalCoins(jsonCurr : Real) : Int64;
+  Begin
+    Result := Round(jsonCurr * 10000);
+  End;
+
+  Function GetBlock(nBlock : Cardinal; jsonObject : TPCJSONObject) : Boolean;
+  var pcops : TPCOperationsComp;
+  begin
+    pcops := TPCOperationsComp.Create(Nil);
+    try
+      If Not TNode.Node.Bank.LoadOperations(pcops,nBlock) then begin
+        ErrorNum := CT_RPC_ErrNum_InternalError;
+        ErrorDesc := 'Cannot load Block: '+IntToStr(nBlock);
+        Result := False;
+        Exit;
+      end;
+      jsonObject.GetAsVariant('block').Value:=pcops.OperationBlock.block;
+      jsonObject.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(pcops.OperationBlock.account_key));
+      jsonObject.GetAsVariant('reward').Value:=ToJSONCurrency(pcops.OperationBlock.reward);
+      jsonObject.GetAsVariant('fee').Value:=ToJSONCurrency(pcops.OperationBlock.fee);
+      jsonObject.GetAsVariant('ver').Value:=pcops.OperationBlock.protocol_version;
+      jsonObject.GetAsVariant('ver_a').Value:=pcops.OperationBlock.protocol_available;
+      jsonObject.GetAsVariant('timestamp').Value:=Int64(pcops.OperationBlock.timestamp);
+      jsonObject.GetAsVariant('target').Value:=Int64(pcops.OperationBlock.compact_target);
+      jsonObject.GetAsVariant('nonce').Value:=Int64(pcops.OperationBlock.nonce);
+      jsonObject.GetAsVariant('payload').Value:=pcops.OperationBlock.block_payload;
+      jsonObject.GetAsVariant('sbh').Value:=TCrypto.ToHexaString(pcops.OperationBlock.initial_safe_box_hash);
+      jsonObject.GetAsVariant('oph').Value:=TCrypto.ToHexaString(pcops.OperationBlock.operations_hash);
+      jsonObject.GetAsVariant('pow').Value:=TCrypto.ToHexaString(pcops.OperationBlock.proof_of_work);
+      jsonObject.GetAsVariant('operations').Value:=pcops.Count;
+      jsonObject.GetAsVariant('hashratekhs').Value := TNode.Node.Bank.SafeBox.CalcBlockHashRateInKhs(pcops.OperationBlock.Block,50);
+      jsonObject.GetAsVariant('maturation').Value := TNode.Node.Bank.BlocksCount - pcops.OperationBlock.block - 1;
+      Result := True;
+    finally
+      pcops.Free;
+    end;
+  end;
+
+  Procedure FillOperationResumeToJSONObject(Const OPR : TOperationResume; jsonObject : TPCJSONObject);
+  Begin
+    jsonObject.GetAsVariant('block').Value:=OPR.Block;
+    jsonObject.GetAsVariant('opblock').Value:=OPR.NOpInsideBlock;
+    jsonObject.GetAsVariant('optype').Value:=OPR.OpType;
+    jsonObject.GetAsVariant('time').Value:=OPR.time;
+    jsonObject.GetAsVariant('account').Value:=OPR.AffectedAccount;
+    jsonObject.GetAsVariant('optxt').Value:=OPR.OperationTxt;
+    jsonObject.GetAsVariant('amount').Value:=ToJSONCurrency(OPR.Amount);
+    jsonObject.GetAsVariant('fee').Value:=ToJSONCurrency(OPR.Fee);
+    if OPR.Balance>=0 then jsonObject.GetAsVariant('balance').Value:=ToJSONCurrency(OPR.Balance);
+    jsonObject.GetAsVariant('payload').Value:=TCrypto.ToHexaString(OPR.OriginalPayload);
+    If OPR.SenderAccount>=0 then begin
+      jsonObject.GetAsVariant('sender_account').Value:=OPR.SenderAccount;
+    end;
+    If OPR.DestAccount>=0 then begin
+      jsonObject.GetAsVariant('dest_account').Value:=OPR.DestAccount;
+    end;
+    If OPR.newKey.EC_OpenSSL_NID>0 then begin
+      jsonObject.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(OPR.newKey));
+    end;
+    jsonObject.GetAsVariant('ophash').Value := TCrypto.ToHexaString(OPR.OperationHash);
+  end;
+
+  Function GetAccountOperations(AccountNumber : Cardinal; jsonArray : TPCJSONArray; MaxBlocksDeep : Integer) : Boolean;
+  var list : TList;
+    Op : TPCOperation;
+    OPR : TOperationResume;
+    Obj : TPCJSONObject;
+    OperationsResume : TOperationsResumeList;
+    i : Integer;
+  Begin
+    OperationsResume := TOperationsResumeList.Create;
+    try
+      list := TList.Create;
+      Try
+        TNode.Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
+        for i := list.Count - 1 downto 0 do begin
+          Op := TNode.Node.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
+          If TPCOperation.OperationToOperationResume(0,Op,AccountNumber,OPR) then begin
+            OPR.NOpInsideBlock := i;
+            OPR.Block := TNode.Node.Operations.OperationBlock.block;
+            OPR.Balance := TNode.Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
+            OperationsResume.Add(OPR);
+          end;
+        end;
+      Finally
+        list.Free;
+      End;
+      TNode.Node.GetStoredOperationsFromAccount(OperationsResume,AccountNumber,MaxBlocksDeep);
+      //
+      for i:=0 to OperationsResume.Count-1 do begin
+        Obj := jsonArray.GetAsObject(i);
+        OPR := OperationsResume[i];
+        FillOperationResumeToJSONObject(OPR,Obj);
+      end;
+      Result := True;
+    finally
+      OperationsResume.Free;
+    end;
+  end;
+  Procedure GetConnections;
+  var i : Integer;
+    l : TList;
+    nc : TNetConnection;
+    obj: TPCJSONObject;
+  Begin
+    l := TNetData.NetData.ConnectionsLock;
+    try
+      for i:=0 to l.Count-1 do begin
+        nc := TNetData.NetData.Connection(i);
+        obj := jsonresponse.GetAsArray('result').GetAsObject(i);
+        obj.GetAsVariant('server').Value := Not (nc is TNetServerClient);
+        obj.GetAsVariant('ip').Value:=nc.Client.RemoteHost;
+        obj.GetAsVariant('port').Value:=nc.Client.RemotePort;
+        obj.GetAsVariant('secs').Value:=UnivDateTimeToUnix(now) - UnivDateTimeToUnix(nc.CreatedTime);
+        obj.GetAsVariant('sent').Value:=nc.Client.BytesSent;
+        obj.GetAsVariant('recv').Value:=nc.Client.BytesReceived;
+        obj.GetAsVariant('appver').Value:=nc.ClientAppVersion;
+        obj.GetAsVariant('netver').Value:=nc.NetProtocolVersion.protocol_version;
+        obj.GetAsVariant('netver_a').Value:=nc.NetProtocolVersion.protocol_available;
+      end;
+    finally
+      TNetData.NetData.ConnectionsUnlock;
+    end;
+  end;
+
+  Function OpSendTo(sender, target : Cardinal; amount, fee : UInt64; RawPayload : TRawBytes; Const Payload_method, EncodePwd : AnsiString) : Boolean;
+  // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+  Var opt : TOpTransaction;
+    sacc,tacc : TAccount;
+    i : Integer;
+    errors : AnsiString;
+    opr : TOperationResume;
+    f_raw : TRawBytes;
+  begin
+    Result := false;
+    if (sender<0) or (sender>=TNode.Node.Bank.AccountsCount) then begin
+      If (sender=CT_MaxAccount) then ErrorDesc := 'Need sender'
+      else ErrorDesc:='Invalid sender account '+Inttostr(sender);
+      ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
+      Exit;
+    end;
+    if (target<0) or (target>=TNode.Node.Bank.AccountsCount) then begin
+      If (target=CT_MaxAccount) then ErrorDesc := 'Need target'
+      else ErrorDesc:='Invalid target account '+Inttostr(target);
+      ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
+      Exit;
+    end;
+    sacc := TNode.Node.Operations.SafeBoxTransaction.Account(sender);
+    tacc := TNode.Node.Operations.SafeBoxTransaction.Account(target);
+    _RPCServer.FWalletKeys.AccountsKeyList.IndexOfAccountKey(sacc.accountkey);
+    i := _RPCServer.FWalletKeys.IndexOfAccountKey(sacc.accountkey);
+    if (i<0) then begin
+      ErrorDesc:='Private key of sender account '+Inttostr(sender)+' not found in wallet';
+      ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
+      Exit;
+    end;
+    if (Not assigned(_RPCServer.FWalletKeys.Key[i].PrivateKey)) then begin
+      if _RPCServer.FWalletKeys.Key[i].CryptedKey<>'' then begin
+        // Wallet is password protected
+        ErrorDesc := 'Wallet is password protected';
+        ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+      end else begin
+        ErrorDesc := 'Wallet private key not found in Wallet';
+        ErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      end;
+      exit;
+    end;
+    if (length(RawPayload)>0) then begin
+      if (Payload_method='none') then f_raw:=RawPayload
+      else if (Payload_method='dest') then begin
+        f_raw := ECIESEncrypt(tacc.accountkey,RawPayload);
+      end else if (Payload_method='sender') then begin
+        f_raw := ECIESEncrypt(sacc.accountkey,RawPayload);
+      end else if (Payload_method='aes') then begin
+        f_raw := TAESComp.EVP_Encrypt_AES256(RawPayload,EncodePwd);
+      end else begin
+        ErrorNum:=CT_RPC_ErrNum_InvalidOperation;
+        ErrorDesc:='Invalid encode payload method: '+Payload_method;
+        exit;
+      end;
+    end else f_raw := '';
+    opt := TOpTransaction.Create(sender,sacc.n_operation+1,target,_RPCServer.FWalletKeys.Key[i].PrivateKey,amount,fee,f_raw);
+    try
+      If not TNode.Node.AddOperation(Nil,opt,errors) then begin
+        ErrorDesc := 'Error adding operation: '+errors;
+        ErrorNum := CT_RPC_ErrNum_InvalidOperation;
+        Exit;
+      end;
+      TPCOperation.OperationToOperationResume(0,opt,sender,opr);
+      FillOperationResumeToJSONObject(opr,GetResultObject);
+      Result := true;
+    finally
+      opt.free;
+    end;
+  end;
+
+  Function ChangeAccountKey(account_number : Cardinal; new_pub_key : TAccountKey; fee : UInt64; RawPayload : TRawBytes; Const Payload_method, EncodePwd : AnsiString) : Boolean;
+  // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+  Var opck : TOpChangeKey;
+    acc : TAccount;
+    i : Integer;
+    errors : AnsiString;
+    opr : TOperationResume;
+    f_raw : TRawBytes;
+  begin
+    Result := false;
+    if (account_number<0) or (account_number>=TNode.Node.Bank.AccountsCount) then begin
+      ErrorDesc:='Invalid account '+Inttostr(account_number);
+      ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
+      Exit;
+    end;
+    acc := TNode.Node.Operations.SafeBoxTransaction.Account(account_number);
+    _RPCServer.FWalletKeys.AccountsKeyList.IndexOfAccountKey(acc.accountkey);
+    i := _RPCServer.FWalletKeys.IndexOfAccountKey(acc.accountkey);
+    if (i<0) then begin
+      ErrorDesc:='Private key of account '+Inttostr(account_number)+' not found in wallet';
+      ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
+      Exit;
+    end;
+    if (Not assigned(_RPCServer.FWalletKeys.Key[i].PrivateKey)) then begin
+      if _RPCServer.FWalletKeys.Key[i].CryptedKey<>'' then begin
+        // Wallet is password protected
+        ErrorDesc := 'Wallet is password protected';
+        ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+      end else begin
+        ErrorDesc := 'Wallet private key not found in Wallet';
+        ErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      end;
+      exit;
+    end;
+    if (length(RawPayload)>0) then begin
+      if (Payload_method='none') then f_raw:=RawPayload
+      else if (Payload_method='dest') then begin
+        f_raw := ECIESEncrypt(new_pub_key,RawPayload);
+      end else if (Payload_method='sender') then begin
+        f_raw := ECIESEncrypt(acc.accountkey,RawPayload);
+      end else if (Payload_method='aes') then begin
+        f_raw := TAESComp.EVP_Encrypt_AES256(RawPayload,EncodePwd);
+      end else begin
+        ErrorNum:=CT_RPC_ErrNum_InvalidOperation;
+        ErrorDesc:='Invalid encode payload method: '+Payload_method;
+        exit;
+      end;
+    end else f_raw := '';
+    opck := TOpChangeKey.Create(account_number,acc.n_operation+1,_RPCServer.FWalletKeys.Key[i].PrivateKey,new_pub_key,fee,f_raw);
+    try
+      If not TNode.Node.AddOperation(Nil,opck,errors) then begin
+        ErrorDesc := 'Error adding operation: '+errors;
+        ErrorNum := CT_RPC_ErrNum_InvalidOperation;
+        Exit;
+      end;
+      TPCOperation.OperationToOperationResume(0,opck,account_number,opr);
+      FillOperationResumeToJSONObject(opr,GetResultObject);
+      Result := true;
+    finally
+      opck.free;
+    end;
+  end;
+
+  Procedure FillAccountObject(Const account : TAccount; jsonObj : TPCJSONObject);
+  Begin
+    jsonObj.GetAsVariant('account').Value:=account.account;
+    jsonObj.GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountkey));
+    jsonObj.GetAsVariant('balance').Value:=ToJSONCurrency(account.balance);
+    jsonObj.GetAsVariant('n_operation').Value:=account.n_operation;
+    jsonObj.GetAsVariant('updated_b').Value:=account.updated_block;
+  end;
+
+  Function DoEncrypt(RawPayload : TRawBytes; pub_key : TAccountKey; Const Payload_method, EncodePwd : AnsiString) : Boolean;
+  Var f_raw : TRawBytes;
+  begin
+    Result := false;
+    if (length(RawPayload)>0) then begin
+      if (Payload_method='none') then f_raw:=RawPayload
+      else if (Payload_method='pubkey') then begin
+        f_raw := ECIESEncrypt(pub_key,RawPayload);
+      end else if (Payload_method='aes') then begin
+        f_raw := TAESComp.EVP_Encrypt_AES256(RawPayload,EncodePwd);
+      end else begin
+        ErrorNum:=CT_RPC_ErrNum_InvalidOperation;
+        ErrorDesc:='Invalid encode payload method: '+Payload_method;
+        exit;
+      end;
+    end else f_raw := '';
+    jsonresponse.GetAsVariant('result').Value := TCrypto.ToHexaString(f_raw);
+    Result := true;
+  end;
+
+  Function DoDecrypt(RawEncryptedPayload : TRawBytes; jsonArrayPwds : TPCJSONArray) : Boolean;
+  var i : Integer;
+    pkey : TECPrivateKey;
+    decrypted_payload : TRawBytes;
+  Begin
+    Result := false;
+    if RawEncryptedPayload='' then begin
+      GetResultObject.GetAsVariant('result').Value:= False;
+      GetResultObject.GetAsVariant('enc_payload').Value:= '';
+      // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+      Result := true;
+      exit;
+    end;
+    for i := 0 to _RPCServer.WalletKeys.Count - 1 do begin
+      pkey := _RPCServer.WalletKeys.Key[i].PrivateKey;
+      if (assigned(pkey)) then begin
+        If ECIESDecrypt(pkey.EC_OpenSSL_NID,pkey.PrivateKey,false,RawEncryptedPayload,decrypted_payload) then begin
+          GetResultObject.GetAsVariant('result').Value:= true;
+          GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
+          GetResultObject.GetAsVariant('unenc_payload').Value:= decrypted_payload;
+          GetResultObject.GetAsVariant('payload_method').Value:= 'key';
+          GetResultObject.GetAsVariant('enc_pubkey').Value:= TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(pkey.PublicKey));
+          // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+          Result := true;
+          exit;
+        end;
+      end;
+    end;
+    for i := 0 to jsonArrayPwds.Count - 1 do begin
+      if TAESComp.EVP_Decrypt_AES256(RawEncryptedPayload,jsonArrayPwds.GetAsVariant(i).AsString(''),decrypted_payload) then begin
+        GetResultObject.GetAsVariant('result').Value:= true;
+        GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
+        GetResultObject.GetAsVariant('unenc_payload').Value:= decrypted_payload;
+        GetResultObject.GetAsVariant('payload_method').Value:= 'pwd';
+        GetResultObject.GetAsVariant('pwd').Value:= jsonArrayPwds.GetAsVariant(i).AsString('');
+        // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+        Result := true;
+        exit;
+      end;
+    end;
+    // Not found
+    GetResultObject.GetAsVariant('result').Value:= False;
+    GetResultObject.GetAsVariant('enc_payload').Value:= TCrypto.ToHexaString(RawEncryptedPayload);
+    Result := true;
+  End;
+
+Var c,c2 : Cardinal;
+  i,j : Integer;
+  account : TAccount;
+  ansistr : AnsiString;
+  nsaarr : TNodeServerAddressArray;
+  pcops : TPCOperationsComp;
+  ecpkey : TECPrivateKey;
+  opr : TOperationResume;
+  r : TRawBytes;
+  ocl : TOrderedCardinalList;
+  jsonarr : TPCJSONArray;
+  jso : TPCJSONObject;
+begin
+  _ro := Nil;
+  ErrorNum:=0;
+  ErrorDesc:='';
+  Result := false;
+  TLog.NewLog(ltdebug,ClassName,'Processing RPC-JSON method '+method);
+  if (method='addnode') then begin
+    // Param "nodes" contains ip's and ports in format "ip1:port1;ip2:port2 ...". If port is not specified, use default
+    // Returns quantity of nodes added
+    TNode.DecodeIpStringToNodeServerAddressArray(params.AsString('nodes',''),nsaarr);
+    for i:=low(nsaarr) to high(nsaarr) do begin
+      TNetData.NetData.AddServer(nsaarr[i]);
+    end;
+    jsonresponse.GetAsVariant('result').Value:=length(nsaarr);
+    Result := true;
+  end else if (method='getaccount') then begin
+    // Param "account" contains account number
+    // Returns JSON Object with account information based on BlockChain + Pending operations
+    c := params.GetAsVariant('account').AsCardinal(CT_MaxAccount);
+    if (c>=0) And (c<TNode.Node.Bank.AccountsCount) then begin
+      account := TNode.Node.Operations.SafeBoxTransaction.Account(c);
+      FillAccountObject(account,GetResultObject);
+      Result := True;
+    end else begin
+      ErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      if (c=CT_MaxAccount) then ErrorDesc := 'Need "account" param'
+      else ErrorDesc := 'Account not found: '+IntToStr(c);
+    end;
+  end else if (method='getwalletaccounts') then begin
+    // Returns JSON array with accounts in Wallet
+    jsonarr := jsonresponse.GetAsArray('result');
+    for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
+      ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
+      for j := 0 to ocl.Count - 1 do begin
+        account := TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(j));
+        FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
+      end;
+    end;
+    Result := true;
+  end else if (method='getwalletpubkeys') then begin
+    // Returns JSON array with pubkeys in wallet
+    jsonarr := jsonresponse.GetAsArray('result');
+    for i:=0 to _RPCServer.WalletKeys.Count-1 do begin
+      jsonarr.GetAsObject(i).GetAsVariant('name').Value := _RPCServer.WalletKeys.Key[i].Name;
+      jsonarr.GetAsObject(i).GetAsVariant('enc_pubkey').Value := TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(_RPCServer.WalletKeys.Key[i].AccountKey));
+      jsonarr.GetAsObject(i).GetAsVariant('can_use').Value := (_RPCServer.WalletKeys.Key[i].CryptedKey<>'');
+    end;
+    Result := true;
+  end else if (method='getblock') then begin
+    // Param "block" contains block number (0..getblockcount-1)
+    // Returns JSON object with block information
+    c := params.GetAsVariant('block').AsCardinal(CT_MaxBlock);
+    if (c>=0) And (c<TNode.Node.Bank.BlocksCount) then begin
+      Result := GetBlock(c,GetResultObject);
+    end else begin
+      ErrorNum := CT_RPC_ErrNum_InvalidBlock;
+      if (c=CT_MaxBlock) then ErrorDesc := 'Need block param'
+      else ErrorDesc := 'Block not found: '+IntToStr(c);
+    end;
+  end else if (method='getblocks') then begin
+    // Param "start" "end" contains blocks number (0..getblockcount-1)
+    // Returns JSON Array with blocks information (limited to 1000 blocks)
+    // Sorted by DESCENDING blocknumber
+    i := params.AsCardinal('last',0);
+    if (i>0) then begin
+      if (i>1000) then i := 1000;
+      c2 := TNode.Node.Bank.BlocksCount-1;
+      if (TNode.Node.Bank.BlocksCount>=i) then
+        c := (TNode.Node.Bank.BlocksCount) - i
+      else c := 0;
+    end else begin
+      c := params.GetAsVariant('start').AsCardinal(CT_MaxBlock);
+      c2 := params.GetAsVariant('end').AsCardinal(CT_MaxBlock);
+    end;
+    if ((c>=0) And (c<TNode.Node.Bank.BlocksCount)) And (c2>=c) And (c2<TNode.Node.Bank.BlocksCount) then begin
+      i := 0; Result := true;
+      while (c<=c2) And (Result) And (i<1000) do begin
+        Result := GetBlock(c2,jsonresponse.GetAsArray('result').GetAsObject(i));
+        dec(c2); inc(i);
+      end;
+    end else begin
+      ErrorNum := CT_RPC_ErrNum_InvalidBlock;
+      if (c>c2) then ErrorDesc := 'Block start > block end'
+      else if (c=CT_MaxBlock) Or (c2=CT_MaxBlock) then ErrorDesc:='Need param "last" or "start" and "end"'
+      else if (c2>=TNode.Node.Bank.BlocksCount) then ErrorDesc := 'Block higher or equal to getblockccount: '+IntToStr(c2)
+      else  ErrorDesc := 'Block not found: '+IntToStr(c);
+    end;
+  end else if (method='getblockcount') then begin
+    // Returns a number with Node blocks count
+    jsonresponse.GetAsVariant('result').Value:=TNode.Node.Bank.BlocksCount;
+    Result := True;
+  end else if (method='getblockoperation') then begin
+    // Param "block" contains block. Null = Pending operation
+    // Param "opblock" contains operation inside a block: (0..getblock.operations-1)
+    // Returns a JSON object with operation values as "Operation resume format"
+    c := params.GetAsVariant('block').AsCardinal(CT_MaxBlock);
+    if (c>=0) And (c<TNode.Node.Bank.BlocksCount) then begin
+      pcops := TPCOperationsComp.Create(Nil);
+      try
+        If Not TNode.Node.Bank.LoadOperations(pcops,c) then begin
+          ErrorNum := CT_RPC_ErrNum_InternalError;
+          ErrorDesc := 'Cannot load Block: '+IntToStr(c);
+          Exit;
+        end;
+        i := params.GetAsVariant('opblock').AsInteger(0);
+        if (i<0) Or (i>=pcops.Count) then begin
+          ErrorNum := CT_RPC_ErrNum_InvalidOperation;
+          ErrorDesc := 'Block/Operation not found: '+IntToStr(c)+'/'+IntToStr(i)+' BlockOperations:'+IntToStr(pcops.Count);
+          Exit;
+        end;
+        If TPCOperation.OperationToOperationResume(c,pcops.Operation[i],pcops.Operation[i].SenderAccount,opr) then begin
+          opr.NOpInsideBlock:=i;
+          opr.time:=pcops.OperationBlock.timestamp;
+          opr.Balance := -1;
+          FillOperationResumeToJSONObject(opr,GetResultObject);
+        end;
+        Result := True;
+      finally
+        pcops.Free;
+      end;
+    end else begin
+      If (c=CT_MaxBlock) then ErrorDesc := 'Need block param'
+      else ErrorDesc := 'Block not found: '+IntToStr(c);
+      ErrorNum := CT_RPC_ErrNum_InvalidBlock;
+    end;
+  end else if (method='getblockoperations') then begin
+    // Param "block" contains block
+    // Returns a JSON array with items as "Operation resume format"
+    c := params.GetAsVariant('block').AsCardinal(CT_MaxBlock);
+    if (c>=0) And (c<TNode.Node.Bank.BlocksCount) then begin
+      pcops := TPCOperationsComp.Create(Nil);
+      try
+        If Not TNode.Node.Bank.LoadOperations(pcops,c) then begin
+          ErrorNum := CT_RPC_ErrNum_InternalError;
+          ErrorDesc := 'Cannot load Block: '+IntToStr(c);
+          Exit;
+        end;
+        GetResultArray;
+        for i := pcops.Count - 1 downto 0 do begin
+          If TPCOperation.OperationToOperationResume(c,pcops.Operation[i],pcops.Operation[i].SenderAccount,opr) then begin
+            opr.NOpInsideBlock:=i;
+            opr.time:=pcops.OperationBlock.timestamp;
+            opr.Balance := -1; // Don't include!
+            FillOperationResumeToJSONObject(opr,GetResultArray.GetAsObject(pcops.Count - 1 - i));
+          end;
+        end;
+        Result := True;
+      finally
+        pcops.Free;
+      end;
+    end else begin
+      If (c=CT_MaxBlock) then ErrorDesc := 'Need block param'
+      else ErrorDesc := 'Block not found: '+IntToStr(c);
+      ErrorNum := CT_RPC_ErrNum_InvalidBlock;
+    end;
+  end else if (method='getaccountoperations') then begin
+    // Returns all the operations affecting an account in "Operation resume format" as an array
+    // Param "account" contains account number
+    // Param "deep" (optional) contains max blocks deep to search (Default: 100)
+    c := params.GetAsVariant('account').AsCardinal(CT_MaxAccount);
+    if ((c>=0) And (c<TNode.Node.Bank.AccountsCount)) then begin
+      Result := GetAccountOperations(c,GetResultArray,params.AsInteger('deep',100));
+    end else begin
+      ErrorNum := CT_RPC_ErrNum_InvalidAccount;
+      If (c=CT_MaxAccount) then ErrorDesc := 'Need account param'
+      else ErrorDesc := 'Account not found: '+IntToStr(c);
+    end;
+  end else if (method='getpendings') then begin
+    // Returns all the operations pending to be included in a block in "Operation resume format" as an array
+    // Create result
+    GetResultArray;
+    for i:=TNode.Node.Operations.Count-1 downto 0 do begin
+      if not TPCOperation.OperationToOperationResume(0,TNode.Node.Operations.Operation[i],TNode.Node.Operations.Operation[i].SenderAccount,opr) then begin
+        ErrorNum := CT_RPC_ErrNum_InternalError;
+        ErrorDesc := 'Error converting data';
+        exit;
+      end;
+      opr.NOpInsideBlock:=i;
+      opr.Balance := TNode.Node.Operations.SafeBoxTransaction.Account(TNode.Node.Operations.Operation[i].SenderAccount).balance;
+      FillOperationResumeToJSONObject(opr,GetResultArray.GetAsObject( TNode.Node.Operations.Count-1-i ));
+    end;
+    Result := true;
+  end else if (method='findoperation') then begin
+    // Search for an operation based on "ophash"
+    r := TCrypto.HexaToRaw(params.AsString('ophash',''));
+    if (r='') then begin
+      ErrorNum:=CT_RPC_ErrNum_NotFound;
+      ErrorDesc:='param ophash not found or invalid value "'+params.AsString('ophash','')+'"';
+      exit;
+    end;
+    pcops := TPCOperationsComp.Create(Nil);
+    try
+      If not TNode.Node.FindOperation(pcops,r,c,i) then begin
+        ErrorNum:=CT_RPC_ErrNum_NotFound;
+        ErrorDesc:='ophash not found: "'+params.AsString('ophash','')+'"';
+        exit;
+      end;
+      If not TPCOperation.OperationToOperationResume(c,pcops.Operation[i],pcops.Operation[i].SenderAccount,opr) then begin
+        ErrorNum := CT_RPC_ErrNum_InternalError;
+        ErrorDesc := 'Error 20161026-1';
+      end;
+      opr.NOpInsideBlock:=i;
+      opr.time:=pcops.OperationBlock.timestamp;
+      FillOperationResumeToJSONObject(opr,GetResultObject);
+      Result := True;
+    finally
+      pcops.Free;
+    end;
+  end else if (method='sendto') then begin
+    // Sends "amount" coins from "sender" to "target" with "fee"
+    // If "payload" is present, it will be encoded using "payload_method"
+    // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+    // Returns a JSON "Operation Resume format" object when successfull
+    // Note: "ophash" will contain block "0" = "pending block"
+    If Not _RPCServer.WalletKeys.IsValidPassword then begin
+      ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+      ErrorDesc := 'Wallet is password protected. Unlock first';
+      exit;
+    end;
+    Result := OpSendTo(params.AsCardinal('sender',CT_MaxAccount),params.AsCardinal('target',CT_MaxAccount),
+       ToPascalCoins(params.AsDouble('amount',0)),
+       ToPascalCoins(params.AsDouble('fee',0)),
+       TCrypto.HexaToRaw(params.AsString('payload','')),
+       params.AsString('payload_method','dest'),params.AsString('pwd',''));
+  end else if (method='changekey') then begin
+    // Change key of "account" to "new_enc_pubkey" (encoded public key format) with "fee"
+    // If "payload" is present, it will be encoded using "payload_method"
+    // "payload_method" types: "none","dest"(default),"sender","aes"(must provide "pwd" param)
+    // Returns a JSON "Operation Resume format" object when successfull
+    // Note: "ophash" will contain block "0" = "pending block"
+    If Not _RPCServer.WalletKeys.IsValidPassword then begin
+      ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+      ErrorDesc := 'Wallet is password protected. Unlock first';
+      exit;
+    end;
+    Result := ChangeAccountKey(params.AsCardinal('account',CT_MaxAccount),
+       TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(params.AsString('new_enc_pubkey',''))),
+       ToPascalCoins(params.AsDouble('fee',0)),
+       TCrypto.HexaToRaw(params.AsString('payload','')),
+       params.AsString('payload_method','dest'),params.AsString('pwd',''));
+  end else if (method='nodestatus') then begin
+    // Returns a JSON Object with Node status
+    GetResultObject.GetAsVariant('ready').Value := False;
+    If TNode.Node.IsReady(ansistr) then begin
+      GetResultObject.GetAsVariant('ready_s').Value := ansistr;
+      if TNetData.NetData.NetStatistics.ActiveConnections>0 then begin
+        GetResultObject.GetAsVariant('ready').Value := True;
+        if TNetData.NetData.IsDiscoveringServers then begin
+          GetResultObject.GetAsVariant('status_s').Value := 'Discovering servers';
+        end else if TNetData.NetData.IsGettingNewBlockChainFromClient then begin
+          GetResultObject.GetAsVariant('status_s').Value := 'Obtaining new blockchain';
+        end else begin
+          GetResultObject.GetAsVariant('status_s').Value := 'Running';
+        end;
+      end else begin
+        GetResultObject.GetAsVariant('ready_s').Value := 'Alone in the world...';
+      end;
+    end else begin
+      GetResultObject.GetAsVariant('ready_s').Value := ansistr;
+    end;
+    GetResultObject.GetAsVariant('port').Value:=TNode.Node.NetServer.Port;
+    GetResultObject.GetAsVariant('locked').Value:=Not _RPCServer.WalletKeys.IsValidPassword;
+    GetResultObject.GetAsVariant('timestamp').Value:=UnivDateTimeToUnix(DateTime2UnivDateTime(now));
+    GetResultObject.GetAsVariant('version').Value:=CT_ClientAppVersion;
+    GetResultObject.GetAsObject('netprotocol').GetAsVariant('ver').Value := CT_NetProtocol_Version;
+    GetResultObject.GetAsObject('netprotocol').GetAsVariant('ver_a').Value := CT_NetProtocol_Available;
+    GetResultObject.GetAsVariant('blocks').Value:=TNode.Node.Bank.BlocksCount;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('active').Value:=TNetData.NetData.NetStatistics.ActiveConnections;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('clients').Value:=TNetData.NetData.NetStatistics.ClientsConnections;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('servers').Value:=TNetData.NetData.NetStatistics.ServersConnectionsWithResponse;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('servers_t').Value:=TNetData.NetData.NetStatistics.ServersConnections;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('total').Value:=TNetData.NetData.NetStatistics.TotalConnections;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('tclients').Value:=TNetData.NetData.NetStatistics.TotalClientsConnections;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('tservers').Value:=TNetData.NetData.NetStatistics.TotalServersConnections;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('breceived').Value:=TNetData.NetData.NetStatistics.BytesReceived;
+    GetResultObject.GetAsObject('netstats').GetAsVariant('bsend').Value:=TNetData.NetData.NetStatistics.BytesSend;
+    nsaarr := TNetData.NetData.GetValidNodeServers;
+    for i := low(nsaarr) to High(nsaarr) do begin
+      jso := GetResultObject.GetAsArray('nodeservers').GetAsObject(i);
+      jso.GetAsVariant('ip').Value := nsaarr[i].ip;
+      jso.GetAsVariant('port').Value := nsaarr[i].port;
+      jso.GetAsVariant('lastcon').Value := nsaarr[i].last_connection;
+      jso.GetAsVariant('attempts').Value := nsaarr[i].total_failed_attemps_to_connect;
+    end;
+    Result := True;
+  end else if (method='encodepubkey') then begin
+    // Creates a encoded public key based on params
+    // Param "ec_nid" can be 714=secp256k1 715=secp384r1 729=secp283k1 716=secp521r1
+    // Param "x","y" are x and y ec public keys values in hexadecimal based on ec_nid
+    // Returns a hexadecimal value containing encoded public key
+    account.accountkey.EC_OpenSSL_NID:=params.AsInteger('ec_nid',0);
+    account.accountkey.x:=TCrypto.HexaToRaw(params.AsString('x',''));
+    account.accountkey.y:=TCrypto.HexaToRaw(params.AsString('y',''));
+    if (account.accountkey.EC_OpenSSL_NID=0) Or (account.accountkey.x='') Or (account.accountkey.y='') then begin
+      ErrorDesc:= 'Need params "ec_nid","x","y" to encodepubkey';
+      ErrorNum:= CT_RPC_ErrNum_InvalidPubKey;
+      exit;
+    end;
+    if TAccountComp.IsValidAccountKey(account.accountkey,ansistr) then begin
+      jsonresponse.GetAsVariant('result').Value:=TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(account.accountkey));
+      Result := True;
+    end else begin
+      ErrorDesc:= ansistr;
+      ErrorNum:= CT_RPC_ErrNum_InvalidPubKey;
+    end;
+  end else if (method='decodepubkey') then begin
+    // Returns "ec_nid", "x" and "y" of an encoded public key (x and y in hexadecimal)
+    // Param "enc_pubkey" is an hexadecimal encoded address (see 'encodepubkey')
+    if (params.AsString('enc_pubkey','')='') then begin
+      ErrorDesc:= 'Need param "enc_pubkey"';
+      ErrorNum:= CT_RPC_ErrNum_InvalidPubKey;
+      exit;
+    end;
+    account.accountkey := CT_Account_NUL.accountkey;
+    account.accountkey := TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(params.AsString('enc_pubkey','')));
+    if (TAccountComp.IsValidAccountKey(account.accountkey,ansistr)) then begin
+      GetResultObject.GetAsVariant('ec_nid').Value := account.accountkey.EC_OpenSSL_NID;
+      GetResultObject.GetAsVariant('x').Value := TCrypto.ToHexaString(account.accountkey.x);
+      GetResultObject.GetAsVariant('y').Value := TCrypto.ToHexaString(account.accountkey.y);
+      Result := True;
+    end else begin
+      ErrorDesc:= ansistr;
+      ErrorNum:= CT_RPC_ErrNum_InvalidPubKey;
+    end;
+  end else if (method='payloadencrypt') then begin
+    // Encrypts a "payload" using "payload_method"
+    // "payload_method" types: "none","pubkey"(must provide "enc_pubkey"),"aes"(must provide "pwd" param)
+    // If payload is "pubkey"
+    // Returns an hexa string with encrypted payload
+    if (params.AsString('payload','')='') then begin
+      ErrorNum:= CT_RPC_ErrNum_InvalidData;
+      ErrorDesc := 'Need param "payload"';
+      exit;
+    end;
+    Result := DoEncrypt(TCrypto.HexaToRaw(params.AsString('payload','')),
+       TAccountComp.RawString2Accountkey(TCrypto.HexaToRaw(params.AsString('enc_pubkey',''))),
+       params.AsString('payload_method',''),params.AsString('pwd',''));
+  end else if (method='payloaddecrypt') then begin
+    // Decrypts a "payload" searching for wallet private keys and for array of strings in "pwds" param
+    // Returns an JSON Object with "result" (Boolean) and
+    if (params.AsString('payload','')='') then begin
+      ErrorNum:= CT_RPC_ErrNum_InvalidData;
+      ErrorDesc := 'Need param "payload"';
+      exit;
+    end;
+    If Not _RPCServer.WalletKeys.IsValidPassword then begin
+      ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+      ErrorDesc := 'Wallet is password protected. Unlock first';
+      exit;
+    end;
+    Result := DoDecrypt(TCrypto.HexaToRaw(params.AsString('payload','')),params.GetAsArray('pwds'));
+  end else if (method='getconnections') then begin
+    // Returns an array of connections objects with info about state
+    GetConnections;
+    Result := true;
+  end else if (method='addnewkey') then begin
+    // Creates a new private key and stores it on the wallet, returning encoded value
+    // Param "ec_nid" can be 714=secp256k1 715=secp384r1 729=secp283k1 716=secp521r1. (Default = CT_Default_EC_OpenSSL_NID)
+    // Param "name" is name for this address
+    If Not _RPCServer.WalletKeys.IsValidPassword then begin
+      ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+      ErrorDesc := 'Wallet is password protected. Unlock first';
+      exit;
+    end;
+    ecpkey := TECPrivateKey.Create;
+    try
+      ecpkey.GenerateRandomPrivateKey(params.AsInteger('ec_nid',CT_Default_EC_OpenSSL_NID));
+      _RPCServer.FWalletKeys.AddPrivateKey(params.AsString('name',DateTimeToStr(now)),ecpkey);
+      jsonresponse.GetAsVariant('result').Value:=TCrypto.ToHexaString(TAccountComp.AccountKey2RawString(ecpkey.PublicKey));
+      Result := true;
+    finally
+      ecpkey.Free;
+    end;
+  end else if (method='unlock') then begin
+    // Unlocks the Wallet with "pwd" password
+    // Returns Boolean if wallet is unlocked
+    if (params.AsString('pwd','')='') then begin
+      ErrorNum:= CT_RPC_ErrNum_InvalidData;
+      ErrorDesc := 'Need param "pwd"';
+      exit;
+    end;
+    If Not _RPCServer.WalletKeys.IsValidPassword then begin
+      _RPCServer.WalletKeys.WalletPassword:=params.AsString('pwd','');
+    end;
+    jsonresponse.GetAsVariant('result').Value := _RPCServer.WalletKeys.IsValidPassword;
+    Result := true;
+  end else if (method='setwalletpassword') then begin
+    // Changes the Wallet password with "pwd" param
+    // Must be unlocked first
+    // Returns Boolean if wallet password changed
+    If Not _RPCServer.WalletKeys.IsValidPassword then begin
+      ErrorNum := CT_RPC_ErrNum_WalletPasswordProtected;
+      ErrorDesc := 'Wallet is password protected. Unlock first';
+      exit;
+    end;
+    //
+    if (params.IndexOfName('pwd')<0) then begin
+      ErrorNum:= CT_RPC_ErrNum_InvalidData;
+      ErrorDesc := 'Need param "pwd"';
+      exit;
+    end;
+    _RPCServer.WalletKeys.WalletPassword:=params.AsString('pwd','');
+    jsonresponse.GetAsVariant('result').Value := _RPCServer.WalletKeys.IsValidPassword;
+    Result := true;
+  end else if (method='stopnode') then begin
+    // Stops communications to other nodes
+    TNode.Node.NetServer.Active := false;
+    TNetData.NetData.NetConnectionsActive:=false;
+    jsonresponse.GetAsVariant('result').Value := true;
+    Result := true;
+  end else if (method='startnode') then begin
+    // Stops communications to other nodes
+    TNode.Node.NetServer.Active := true;
+    TNetData.NetData.NetConnectionsActive:=true;
+    jsonresponse.GetAsVariant('result').Value := true;
+    Result := true;
+  end else begin
+    ErrorNum := CT_RPC_ErrNum_MethodNotFound;
+    ErrorDesc := 'Method not found: "'+method+'"';
+  end;
+end;
+
+{ TRPCServerThread }
+
+procedure TRPCServerThread.BCExecute;
+var
+  ClientSock:TSocket;
+begin
+  with FServerSocket do begin
+    CreateSocket;
+    setLinger(true,10000);
+    bind('0.0.0.0',Inttostr(FPort));
+    listen;
+    repeat
+      if terminated then break;
+      Try
+        if canread(1000) then begin
+          ClientSock:=accept;
+          if lastError=0 then TRPCProcess.create(ClientSock);
+        end;
+      Except
+        On E:Exception do begin
+          TLog.NewLog(ltError,Classname,'Error '+E.ClassName+':'+E.Message);
+        end;
+      End;
+      sleep(1);
+    until false;
+  end;
+end;
+
+constructor TRPCServerThread.Create(Port: Word);
+begin
+  TLog.NewLog(ltInfo,ClassName,'Activating RPC-JSON Server on port '+inttostr(Port));
+  FServerSocket:=TTCPBlockSocket.create;
+  FPort := Port;
+  inherited create(false);
+end;
+
+destructor TRPCServerThread.Destroy;
+begin
+  TLog.NewLog(ltInfo,ClassName,'Stoping RPC-JSON Server');
+  FreeAndNil(FServerSocket);
+  inherited Destroy;
+end;
+
 end.
 end.

+ 69 - 12
Units/PascalCoin/UServerApp.pas

@@ -1,5 +1,9 @@
 unit UServerApp;
 unit UServerApp;
 
 
+{$IFDEF FPC}
+  {$MODE Delphi}
+{$ENDIF}
+
 {$IFDEF MSWINDOWS}
 {$IFDEF MSWINDOWS}
   {$DEFINE OS_MSWIN}
   {$DEFINE OS_MSWIN}
 {$ENDIF}
 {$ENDIF}
@@ -7,11 +11,16 @@ unit UServerApp;
 interface
 interface
 
 
 uses
 uses
+  {$IFDEF LCL}
+  interfaces,
+  {$ENDIF}
   {$IFDEF OS_MSWIN}
   {$IFDEF OS_MSWIN}
   Windows,
   Windows,
   Messages,
   Messages,
   {$ENDIF}
   {$ENDIF}
-  SyncObjs;
+  SyncObjs,
+  UOpenSSL, UCrypto, UNode, UFileStorage, UFolderHelper, UWalletKeys, UConst, ULog, UNetProtocol,
+  URPC;
 
 
 type
 type
   TPascalCoinServerLogType = (sltDebug, sltInfo, sltError, sltWarning);
   TPascalCoinServerLogType = (sltDebug, sltInfo, sltError, sltWarning);
@@ -19,14 +28,20 @@ type
   TPascalCoinServerAppLogEvent = procedure (LogType: TPascalCoinServerLogType;
   TPascalCoinServerAppLogEvent = procedure (LogType: TPascalCoinServerLogType;
       Msg: String; Level: Integer) of object;
       Msg: String; Level: Integer) of object;
 
 
+  { TPascalCoinServerApp }
+
   TPascalCoinServerApp = class
   TPascalCoinServerApp = class
   private
   private
     FLock : TCriticalSection;
     FLock : TCriticalSection;
+    FOnLog: TPascalCoinServerAppLogEvent;
     FTerminated : Boolean;
     FTerminated : Boolean;
     {$IFDEF OS_MSWIN}
     {$IFDEF OS_MSWIN}
     hStdIn : THandle;
     hStdIn : THandle;
     {$ENDIF}
     {$ENDIF}
-    FOnLog : TPascalCoinServerAppLogEvent;
+    FNode : TNode;
+    FWalletKeys : TWalletKeysExt;
+    FRPC : TRPCServer;
+    FLog : TLog;
 
 
     procedure Lock;
     procedure Lock;
     procedure Unlock;
     procedure Unlock;
@@ -35,6 +50,7 @@ type
               const Level: Integer = 0); overload;
               const Level: Integer = 0); overload;
     procedure Log(const LogType: TPascalCoinServerLogType; const Msg: String;
     procedure Log(const LogType: TPascalCoinServerLogType; const Msg: String;
               const Params: array of const; const Level: Integer = 0); overload;
               const Params: array of const; const Level: Integer = 0); overload;
+    procedure OnPascalCoinLog(logtype : TLogType; Time : TDateTime; ThreadID : Cardinal; Const sender, logtext : AnsiString);
 
 
     function  GetTerminated: Boolean;
     function  GetTerminated: Boolean;
     procedure SetTerminated;
     procedure SetTerminated;
@@ -49,13 +65,12 @@ type
     constructor Create;
     constructor Create;
     destructor Destroy; override;
     destructor Destroy; override;
 
 
-    property  OnLog: TPascalCoinServerAppLogEvent read FOnLog write FOnLog;
-
     procedure Init;
     procedure Init;
     procedure Run;
     procedure Run;
     procedure Stop;
     procedure Stop;
 
 
     property  Terminated: Boolean read GetTerminated;
     property  Terminated: Boolean read GetTerminated;
+    property  OnLog: TPascalCoinServerAppLogEvent read FOnLog write FOnLog;
   end;
   end;
 
 
 var
 var
@@ -64,7 +79,7 @@ var
 implementation
 implementation
 
 
 uses
 uses
-  SysUtils;
+  SysUtils, Classes;
 
 
 { TPascalCoinServerApp }
 { TPascalCoinServerApp }
 
 
@@ -72,14 +87,20 @@ constructor TPascalCoinServerApp.Create;
 begin
 begin
   inherited Create;
   inherited Create;
   FLock := TCriticalSection.Create;
   FLock := TCriticalSection.Create;
+  FLog := TLog.Create(Nil);
+  FLog.OnInThreadNewLog:=OnPascalCoinLog;
   {$IFDEF OS_MSWIN}
   {$IFDEF OS_MSWIN}
   // get the console input handle
   // get the console input handle
   hStdIn := GetStdHandle(STD_INPUT_HANDLE);
   hStdIn := GetStdHandle(STD_INPUT_HANDLE);
   {$ENDIF}
   {$ENDIF}
+  FWalletKeys := TWalletKeysExt.Create(Nil);
 end;
 end;
 
 
 destructor TPascalCoinServerApp.Destroy;
 destructor TPascalCoinServerApp.Destroy;
 begin
 begin
+  FreeAndNil(FWalletKeys);
+  FLog.OnNewLog:=Nil;
+  FreeAndNil(FLog);
   FreeAndNil(FLock);
   FreeAndNil(FLock);
   inherited Destroy;
   inherited Destroy;
 end;
 end;
@@ -89,8 +110,13 @@ begin
   FLock.Acquire;
   FLock.Acquire;
 end;
 end;
 
 
+procedure TPascalCoinServerApp.Unlock;
+begin
+  FLock.Release;
+end;
+
 procedure TPascalCoinServerApp.Log(const LogType: TPascalCoinServerLogType;
 procedure TPascalCoinServerApp.Log(const LogType: TPascalCoinServerLogType;
-          const Msg: String; const Level: Integer);
+  const Msg: String; const Level: Integer);
 begin
 begin
   if Assigned(FOnLog) then
   if Assigned(FOnLog) then
     FOnLog(LogType, Msg, Level);
     FOnLog(LogType, Msg, Level);
@@ -102,9 +128,13 @@ begin
   Log(LogType, Format(Msg, Params), Level);
   Log(LogType, Format(Msg, Params), Level);
 end;
 end;
 
 
-procedure TPascalCoinServerApp.Unlock;
+procedure TPascalCoinServerApp.OnPascalCoinLog(logtype: TLogType;
+  Time: TDateTime; ThreadID: Cardinal; const sender, logtext: AnsiString);
+Var s : AnsiString;
 begin
 begin
-  FLock.Release;
+  if (logtype=ltdebug)  then exit;
+  if ThreadID=MainThreadID then s := ' MAIN:' else s:=' TID:';
+  Log(sltInfo,s+IntToHex(ThreadID,8)+' ['+CT_LogType[Logtype]+'] <'+sender+'> '+logtext);
 end;
 end;
 
 
 function TPascalCoinServerApp.GetTerminated: Boolean;
 function TPascalCoinServerApp.GetTerminated: Boolean;
@@ -233,20 +263,47 @@ end;
 
 
 procedure TPascalCoinServerApp.Init;
 procedure TPascalCoinServerApp.Init;
 begin
 begin
-  Log(sltInfo, 'PascalCoin Server');
+  TLog.NewLog(ltinfo,Classname,'PascalCoin Server');
+  // Load Node
+  // Check OpenSSL dll
+  if Not LoadSSLCrypt then raise Exception.Create('Cannot load '+SSL_C_LIB+#10+'To use this software make sure this file is available on you system or reinstall the application');
+  TCrypto.InitCrypto;
+  FWalletKeys.WalletFileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'WalletKeys.dat';
+  // Creating Node:
+  FNode := TNode.Node;
+  // RPC Server
+  Log(sltInfo,'Activating RPC server');
+  FRPC := TRPCServer.Create;
+  FRPC.WalletKeys := FWalletKeys;
+  FRPC.Active:=true;
+  // Check Database
+  FNode.Bank.StorageClass := TFileStorage;
+  TFileStorage(FNode.Bank.Storage).DatabaseFolder := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'Data';
+  // Reading database
+  Log(sltInfo,'Reading database and constructing PascalCoin accounts');
+  FNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
+  FWalletKeys.SafeBox := FNode.Node.Bank.SafeBox;
+  Log(sltInfo,'Start discovering nodes');
+  FNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
+  FNode.Node.NetServer.Active := true;
 end;
 end;
 
 
 procedure TPascalCoinServerApp.Run;
 procedure TPascalCoinServerApp.Run;
 begin
 begin
-  Log(sltInfo, 'Start');
-  Log(sltInfo, 'Running (press Q to stop)');
+  Log(sltinfo,'Start');
+  Log(sltinfo,'Running (press Q to stop)');
   while not GetTerminated do
   while not GetTerminated do
     ProcessOrWait;
     ProcessOrWait;
 end;
 end;
 
 
 procedure TPascalCoinServerApp.Stop;
 procedure TPascalCoinServerApp.Stop;
 begin
 begin
-  Log(sltInfo, 'Stop');
+  Log(sltinfo,'Stop');
+  FreeAndNil(FRPC);
+  FNode.NetServer.Active := false;
+  TNetData.NetData.Free;
+  FreeAndNil(FNode);
+  Log(sltinfo,'Finalized');
 end;
 end;
 
 
 end.
 end.

+ 13 - 5
Units/PascalCoin/UTCPIP.pas

@@ -51,6 +51,7 @@ type
     FRemoteHost : AnsiString;
     FRemoteHost : AnsiString;
     FRemotePort : Word;
     FRemotePort : Word;
     FBytesReceived, FBytesSent : Int64;
     FBytesReceived, FBytesSent : Int64;
+    FLock : TCriticalSection;
     {$ENDIF}
     {$ENDIF}
     FOnConnect: TNotifyEvent;
     FOnConnect: TNotifyEvent;
     FOnDisconnect: TNotifyEvent;
     FOnDisconnect: TNotifyEvent;
@@ -188,7 +189,7 @@ uses
 {$IFnDEF FPC}
 {$IFnDEF FPC}
   Windows,
   Windows,
 {$ELSE}
 {$ELSE}
-  LCLIntf, LCLType, LMessages,
+  {LCLIntf, LCLType, LMessages,}
 {$ENDIF}
 {$ENDIF}
   UConst, ULog;
   UConst, ULog;
 
 
@@ -263,6 +264,7 @@ begin
   FTcpBlockSocket.OnError := TCustomIpClient_OnError;
   FTcpBlockSocket.OnError := TCustomIpClient_OnError;
   {$ENDIF}
   {$ENDIF}
   {$IFDEF Synapse}
   {$IFDEF Synapse}
+  FLock := TCriticalSection.Create;
   FTcpBlockSocket := TTCPBlockSocket.Create;
   FTcpBlockSocket := TTCPBlockSocket.Create;
   FTcpBlockSocket.OnAfterConnect := OnConnect;
   FTcpBlockSocket.OnAfterConnect := OnConnect;
   FTcpBlockSocket.SocksTimeout := 10000;
   FTcpBlockSocket.SocksTimeout := 10000;
@@ -277,6 +279,7 @@ end;
 destructor TNetTcpIpClient.Destroy;
 destructor TNetTcpIpClient.Destroy;
 begin
 begin
   Disconnect;
   Disconnect;
+  FreeAndNil(FLock);
   inherited;
   inherited;
   FreeAndNil(FTcpBlockSocket);
   FreeAndNil(FTcpBlockSocket);
   TLog.NewLog(ltdebug,ClassName,'Destroying Socket end');
   TLog.NewLog(ltdebug,ClassName,'Destroying Socket end');
@@ -288,10 +291,15 @@ begin
   FTcpBlockSocket.Disconnect;
   FTcpBlockSocket.Disconnect;
   {$ENDIF}
   {$ENDIF}
   {$IFDEF Synapse}
   {$IFDEF Synapse}
-  if Not FConnected then exit;
-  FConnected := false;
-  FTcpBlockSocket.CloseSocket;
-  if Assigned(FOnDisconnect) then FOnDisconnect(Self);
+  FLock.Acquire;
+  Try
+    if Not FConnected then exit;
+    FConnected := false;
+    FTcpBlockSocket.CloseSocket;
+    if Assigned(FOnDisconnect) then FOnDisconnect(Self);
+  Finally
+    FLock.Release;
+  End;
   {$ENDIF}
   {$ENDIF}
 end;
 end;
 
 

+ 94 - 4
Units/PascalCoin/UWalletKeys.pas

@@ -52,17 +52,35 @@ Type
     Procedure SaveToStream(Stream : TStream);
     Procedure SaveToStream(Stream : TStream);
     Property IsValidPassword : Boolean read FIsValidPassword;
     Property IsValidPassword : Boolean read FIsValidPassword;
     Property WalletPassword : AnsiString read FWalletPassword write SetWalletPassword;
     Property WalletPassword : AnsiString read FWalletPassword write SetWalletPassword;
-    Function AddPrivateKey(Const Name : AnsiString; ECPrivateKey : TECPrivateKey) : Integer;
-    Function AddPublicKey(Const Name : AnsiString; ECDSA_Public : TECDSA_Public) : Integer;
+    Function AddPrivateKey(Const Name : AnsiString; ECPrivateKey : TECPrivateKey) : Integer; virtual;
+    Function AddPublicKey(Const Name : AnsiString; ECDSA_Public : TECDSA_Public) : Integer; virtual;
     Function IndexOfAccountKey(AccountKey : TAccountKey) : Integer;
     Function IndexOfAccountKey(AccountKey : TAccountKey) : Integer;
-    Procedure Delete(index : Integer);
-    Procedure Clear;
+    Procedure Delete(index : Integer); virtual;
+    Procedure Clear; virtual;
     Function Count : Integer;
     Function Count : Integer;
     Property WalletFileName : AnsiString read FWalletFileName write SetWalletFileName;
     Property WalletFileName : AnsiString read FWalletFileName write SetWalletFileName;
     Property OnChanged : TNotifyEvent read FOnChanged write FOnChanged;
     Property OnChanged : TNotifyEvent read FOnChanged write FOnChanged;
     Procedure SetName(index : Integer; Const newName : AnsiString);
     Procedure SetName(index : Integer; Const newName : AnsiString);
   End;
   End;
 
 
+  TWalletKeysExt = Class(TWalletKeys)
+  private
+    FOrderedAccountKeysList : TOrderedAccountKeysList;
+    procedure SetSafeBox(const Value: TPCSafeBox);
+    function GetSafeBox: TPCSafeBox;
+  public
+    Constructor Create(AOwner : TComponent); override;
+    Destructor destroy; override;
+    Function AddPrivateKey(Const Name : AnsiString; ECPrivateKey : TECPrivateKey) : Integer; override;
+    Function AddPublicKey(Const Name : AnsiString; ECDSA_Public : TECDSA_Public) : Integer; override;
+    Procedure Delete(index : Integer); override;
+    Procedure Clear; override;
+    //
+    Property AccountsKeyList : TOrderedAccountKeysList read FOrderedAccountKeysList;
+    Property SafeBox : TPCSafeBox read GetSafeBox write SetSafeBox;
+  End;
+
+
 Const CT_TWalletKey_NUL  : TWalletKey = (Name:'';AccountKey:(EC_OpenSSL_NID:0;x:'';y:'');CryptedKey:'';PrivateKey:Nil);
 Const CT_TWalletKey_NUL  : TWalletKey = (Name:'';AccountKey:(EC_OpenSSL_NID:0;x:'';y:'');CryptedKey:'';PrivateKey:Nil);
 
 
 implementation
 implementation
@@ -323,4 +341,76 @@ begin
   if FIsValidPassword then SaveToStream(FWalletFileStream);
   if FIsValidPassword then SaveToStream(FWalletFileStream);
 end;
 end;
 
 
+{ TWalletKeysExt }
+
+function TWalletKeysExt.AddPrivateKey(const Name: AnsiString;
+  ECPrivateKey: TECPrivateKey): Integer;
+begin
+  Result := inherited AddPrivateKey(Name,ECPrivateKey);
+  if Assigned(FOrderedAccountKeysList) then begin
+    FOrderedAccountKeysList.AddAccountKey(ECPrivateKey.PublicKey);
+  end;
+end;
+
+function TWalletKeysExt.AddPublicKey(const Name: AnsiString;
+  ECDSA_Public: TECDSA_Public): Integer;
+begin
+  Result := inherited AddPublicKey(Name,ECDSA_Public);
+  if Assigned(FOrderedAccountKeysList) then begin
+    FOrderedAccountKeysList.AddAccountKey(ECDSA_Public);
+  end;
+end;
+
+procedure TWalletKeysExt.Clear;
+begin
+  inherited;
+  if Assigned(FOrderedAccountKeysList) then begin
+    FOrderedAccountKeysList.Clear;
+  end;
+end;
+
+constructor TWalletKeysExt.Create(AOwner: TComponent);
+begin
+  inherited;
+  FOrderedAccountKeysList := Nil;
+end;
+
+procedure TWalletKeysExt.Delete(index: Integer);
+begin
+  if Assigned(FOrderedAccountKeysList) then begin
+    FOrderedAccountKeysList.RemoveAccountKey( Key[index].AccountKey );
+  end;
+  inherited;
+end;
+
+destructor TWalletKeysExt.destroy;
+begin
+  FreeAndnil(FOrderedAccountKeysList);
+  inherited;
+end;
+
+function TWalletKeysExt.GetSafeBox: TPCSafeBox;
+begin
+  Result := Nil;
+  if Assigned(FOrderedAccountKeysList) then begin
+    Result := FOrderedAccountKeysList.SafeBox;
+  end;
+end;
+
+procedure TWalletKeysExt.SetSafeBox(const Value: TPCSafeBox);
+Var i : Integer;
+begin
+  if Assigned(FOrderedAccountKeysList) then begin
+    if FOrderedAccountKeysList.SafeBox<>Value then FreeAndNil(FOrderedAccountKeysList)
+    else exit;
+  end;
+  if Assigned(Value) then begin
+    // Initialize
+    FOrderedAccountKeysList := TOrderedAccountKeysList.Create(Value,false);
+    for i := 0 to Count - 1 do begin
+      FOrderedAccountKeysList.AddAccountKey(Key[i].AccountKey);
+    end;
+  end;
+end;
+
 end.
 end.

+ 3 - 1
Units/Utils/UFolderHelper.pas

@@ -61,7 +61,7 @@ uses
   Windows,
   Windows,
   {$DEFINE FILEVERSIONINFO}
   {$DEFINE FILEVERSIONINFO}
   {$ENDIF}
   {$ENDIF}
-  LCLIntf, LCLType, LMessages,
+  {LCLIntf, LCLType, LMessages,}
 {$ENDIF}
 {$ENDIF}
   SysUtils;
   SysUtils;
 
 
@@ -104,6 +104,7 @@ begin
 end;
 end;
 
 
 class function TFolderHelper.GetTFileVersionInfo(Const FileName: String): TFileVersionInfo;
 class function TFolderHelper.GetTFileVersionInfo(Const FileName: String): TFileVersionInfo;
+{$IFDEF FILEVERSIONINFO}
 Var verInfoSize : DWord;
 Var verInfoSize : DWord;
     GetInfoSizeJunk : DWord;
     GetInfoSizeJunk : DWord;
     VersionInfo,
     VersionInfo,
@@ -111,6 +112,7 @@ Var verInfoSize : DWord;
     InfoPointer : Pointer;
     InfoPointer : Pointer;
     VersionInfoSize: UINT;
     VersionInfoSize: UINT;
     VersionValue :  string;
     VersionValue :  string;
+{$ENDIF}
 Begin
 Begin
    With result do
    With result do
    Begin
    Begin

+ 4 - 91
Units/Utils/UGridUtils.pas

@@ -94,7 +94,6 @@ Type
 
 
     procedure SetBlockEnd(const Value: Int64);
     procedure SetBlockEnd(const Value: Int64);
     procedure SetBlockStart(const Value: Int64);protected
     procedure SetBlockStart(const Value: Int64);protected
-    Procedure GetStoredOperationsFromAccount(Const OperationsResume : TOperationsResumeList; account_number : Cardinal; MaxDeep : Integer); virtual;
   protected
   protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
     procedure Notification(AComponent: TComponent; Operation: TOperation); Override;
   public
   public
@@ -360,25 +359,6 @@ Begin
   ts.Opaque:=false;
   ts.Opaque:=false;
   ts.ShowPrefix:= not (tfNoPrefix in TextFormat);
   ts.ShowPrefix:= not (tfNoPrefix in TextFormat);
   ts.SystemFont:=false;
   ts.SystemFont:=false;
-  { XXXXXXXXXXX
-  if (gdSelected in State) Or (gdFocused in State) then begin
-    if (gdFocused in State) then begin
-      Canvas.Font.Color:=clHighlightText;
-    end;
-    if (State=[gdSelected]) then begin
-      Canvas.Font.Color:=clHighlightText;
-    end else begin
-      Canvas.Brush.Color:= clHighlight;
-      Canvas.Font.Color:=clHighlightText;
-    end;
-    Canvas.Brush.Color:= clHighlight;
-    Canvas.Font.Color:=clHighlightText;
-  end else if (gdRowHighlight in State) then begin
-    Canvas.Brush.Color:= clHighlight;
-    Canvas.Font.Color:=clHighlightText;
-  end;
-  Canvas.FillRect(Rect);
-  }
   Canvas.TextRect(Rect,Rect.Left,Rect.Top,Text,ts);
   Canvas.TextRect(Rect,Rect.Left,Rect.Top,Text,ts);
 end;
 end;
 {$ELSE}
 {$ELSE}
@@ -574,73 +554,6 @@ begin
   Result := FNodeNotifyEvents.Node;
   Result := FNodeNotifyEvents.Node;
 end;
 end;
 
 
-procedure TOperationsGrid.GetStoredOperationsFromAccount(const OperationsResume: TOperationsResumeList; account_number: Cardinal; MaxDeep : Integer);
-  Procedure DoGetFromBlock(block_number : Cardinal; last_balance : Int64; act_deep : Integer);
-  var opc : TPCOperationsComp;
-    op : TPCOperation;
-    OPR : TOperationResume;
-    l : TList;
-    i : Integer;
-    next_block_number : Cardinal;
-  begin
-    if (act_deep<=0) Or ((block_number<=0) And (block_number>0)) then exit;
-
-    opc := TPCOperationsComp.Create(Nil);
-    Try
-      If not Node.Bank.Storage.LoadBlockChainBlock(opc,block_number) then begin
-        TLog.NewLog(lterror,ClassName,'Error searching for block '+inttostr(block_number));
-        exit;
-      end;
-      l := TList.Create;
-      try
-        next_block_number := 0;
-        opc.OperationsHashTree.GetOperationsAffectingAccount(account_number,l);
-        for i := l.Count - 1 downto 0 do begin
-          op := opc.Operation[PtrInt(l.Items[i])];
-          if (i=0) then begin
-            If op.SenderAccount=account_number then next_block_number := op.Previous_Sender_updated_block
-            else next_block_number := op.Previous_Destination_updated_block;
-          end;
-          If TPCOperation.OperationToOperationResume(Op,account_number,OPR) then begin
-            OPR.NOpInsideBlock := i;
-            OPR.time := opc.OperationBlock.timestamp;
-            OPR.Block := block_number;
-            OPR.Balance := last_balance;
-            last_balance := last_balance - ( OPR.Amount + OPR.Fee );
-            OperationsResume.Add(OPR);
-          end;
-        end;
-        // Is a new block operation?
-        if (TAccountComp.AccountBlock(account_number)=block_number) And ((account_number MOD CT_AccountsPerBlock)=0) then begin
-          OPR := CT_TOperationResume_NUL;
-          OPR.Block := block_number;
-          OPR.time := opc.OperationBlock.timestamp;
-          OPR.AffectedAccount := account_number;
-          OPR.Amount := opc.OperationBlock.reward;
-          OPR.Fee := opc.OperationBlock.fee;
-          OPR.Balance := last_balance;
-          OPR.OperationTxt := 'Blockchain reward';
-          OperationsResume.Add(OPR);
-        end;
-        //
-        opc.Clear(true);
-        if (next_block_number>0) And (next_block_number<block_number) And (act_deep>0) then DoGetFromBlock(next_block_number,last_balance,act_deep-1);
-      finally
-        l.Free;
-      end;
-    Finally
-      opc.Free;
-    End;
-  end;
-
-Var acc : TAccount;
-begin
-  if MaxDeep<0 then exit;
-  if account_number>=Node.Bank.SafeBox.AccountsCount then exit;
-  acc := Node.Bank.SafeBox.Account(account_number);
-  if (acc.updated_block>0) Or (acc.account=0) then DoGetFromBlock(acc.updated_block,acc.balance,MaxDeep);
-end;
-
 procedure TOperationsGrid.InitGrid;
 procedure TOperationsGrid.InitGrid;
 begin
 begin
   if Not Assigned(FDrawGrid) then exit;
   if Not Assigned(FDrawGrid) then exit;
@@ -887,7 +800,7 @@ begin
     if FPendingOperations then begin
     if FPendingOperations then begin
       for i := Node.Operations.Count - 1 downto 0 do begin
       for i := Node.Operations.Count - 1 downto 0 do begin
         Op := Node.Operations.OperationsHashTree.GetOperation(i);
         Op := Node.Operations.OperationsHashTree.GetOperation(i);
-        If TPCOperation.OperationToOperationResume(Op,Op.SenderAccount,OPR) then begin
+        If TPCOperation.OperationToOperationResume(0,Op,Op.SenderAccount,OPR) then begin
           OPR.NOpInsideBlock := i;
           OPR.NOpInsideBlock := i;
           OPR.Block := Node.Operations.OperationBlock.block;
           OPR.Block := Node.Operations.OperationBlock.block;
           OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
           OPR.Balance := Node.Operations.SafeBoxTransaction.Account(Op.SenderAccount).balance;
@@ -924,7 +837,7 @@ begin
               FOperationsResume.Add(OPR);
               FOperationsResume.Add(OPR);
               // Reverse operations inside a block
               // Reverse operations inside a block
               for i := opc.Count - 1 downto 0 do begin
               for i := opc.Count - 1 downto 0 do begin
-                if TPCOperation.OperationToOperationResume(opc.Operation[i],opc.Operation[i].SenderAccount,opr) then begin
+                if TPCOperation.OperationToOperationResume(bend,opc.Operation[i],opc.Operation[i].SenderAccount,opr) then begin
                   opr.NOpInsideBlock := i;
                   opr.NOpInsideBlock := i;
                   opr.Block := bend;
                   opr.Block := bend;
                   opr.time := opc.OperationBlock.timestamp;
                   opr.time := opc.OperationBlock.timestamp;
@@ -944,7 +857,7 @@ begin
           Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
           Node.Operations.OperationsHashTree.GetOperationsAffectingAccount(AccountNumber,list);
           for i := list.Count - 1 downto 0 do begin
           for i := list.Count - 1 downto 0 do begin
             Op := Node.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
             Op := Node.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
-            If TPCOperation.OperationToOperationResume(Op,AccountNumber,OPR) then begin
+            If TPCOperation.OperationToOperationResume(0,Op,AccountNumber,OPR) then begin
               OPR.NOpInsideBlock := i;
               OPR.NOpInsideBlock := i;
               OPR.Block := Node.Operations.OperationBlock.block;
               OPR.Block := Node.Operations.OperationBlock.block;
               OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
               OPR.Balance := Node.Operations.SafeBoxTransaction.Account(AccountNumber).balance;
@@ -954,7 +867,7 @@ begin
         Finally
         Finally
           list.Free;
           list.Free;
         End;
         End;
-        GetStoredOperationsFromAccount(FOperationsResume,AccountNumber,100);
+        Node.GetStoredOperationsFromAccount(FOperationsResume,AccountNumber,100);
       end;
       end;
     end;
     end;
   Finally
   Finally

+ 56 - 15
Units/Utils/UJSONFunctions.pas

@@ -50,6 +50,8 @@ Type
 
 
   TPCJSONDataClass = Class of TPCJSONData;
   TPCJSONDataClass = Class of TPCJSONData;
 
 
+  { TPCJSONVariantValue }
+
   TPCJSONVariantValue = Class(TPCJSONData)
   TPCJSONVariantValue = Class(TPCJSONData)
   private
   private
     FOldValue : Variant;
     FOldValue : Variant;
@@ -64,10 +66,12 @@ Type
     Property Value : Variant read FValue write SetValue;
     Property Value : Variant read FValue write SetValue;
     Function AsString(DefValue : String) : String;
     Function AsString(DefValue : String) : String;
     Function AsInteger(DefValue : Integer) : Integer;
     Function AsInteger(DefValue : Integer) : Integer;
+    Function AsInt64(DefValue : Int64) : Int64;
     Function AsDouble(DefValue : Double) : Double;
     Function AsDouble(DefValue : Double) : Double;
     Function AsBoolean(DefValue : Boolean) : Boolean;
     Function AsBoolean(DefValue : Boolean) : Boolean;
     Function AsDateTime(DefValue : TDateTime) : TDateTime;
     Function AsDateTime(DefValue : TDateTime) : TDateTime;
     Function AsCurrency(DefValue : Currency) : Currency;
     Function AsCurrency(DefValue : Currency) : Currency;
+    Function AsCardinal(DefValue : Cardinal) : Cardinal;
   End;
   End;
 
 
   TPCJSONNameValue = Class(TPCJSONData)
   TPCJSONNameValue = Class(TPCJSONData)
@@ -143,6 +147,8 @@ Type
     Function GetAsArray(Name : String) : TPCJSONArray;
     Function GetAsArray(Name : String) : TPCJSONArray;
     Function AsString(ParamName : String; DefValue : String) : String;
     Function AsString(ParamName : String; DefValue : String) : String;
     Function AsInteger(ParamName : String; DefValue : Integer) : Integer;
     Function AsInteger(ParamName : String; DefValue : Integer) : Integer;
+    Function AsCardinal(ParamName : String; DefValue : Cardinal) : Cardinal;
+    Function AsInt64(ParamName : String; DefValue : Int64) : Int64;
     Function AsDouble(ParamName : String; DefValue : Double) : Double;
     Function AsDouble(ParamName : String; DefValue : Double) : Double;
     Function AsBoolean(ParamName : String; DefValue : Boolean) : Boolean;
     Function AsBoolean(ParamName : String; DefValue : Boolean) : Boolean;
     Function AsDateTime(ParamName : String; DefValue : TDateTime) : TDateTime;
     Function AsDateTime(ParamName : String; DefValue : TDateTime) : TDateTime;
@@ -408,6 +414,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TPCJSONVariantValue.AsCardinal(DefValue: Cardinal): Cardinal;
+begin
+  Result := Cardinal( StrToIntDef(VarToStrDef(Value,''),DefValue) );
+end;
+
 function TPCJSONVariantValue.AsDateTime(DefValue: TDateTime): TDateTime;
 function TPCJSONVariantValue.AsDateTime(DefValue: TDateTime): TDateTime;
 begin
 begin
   try
   try
@@ -426,13 +437,14 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TPCJSONVariantValue.AsInt64(DefValue: Int64): Int64;
+begin
+  Result := StrToInt64Def(VarToStrDef(Value,''),DefValue);
+end;
+
 function TPCJSONVariantValue.AsInteger(DefValue: Integer): Integer;
 function TPCJSONVariantValue.AsInteger(DefValue: Integer): Integer;
 begin
 begin
-  try
-    Result := VarAsType(Value,varInteger);
-  except
-    Result := DefValue;
-  end;
+  Result := StrToIntDef(VarToStrDef(Value,''),DefValue);
 end;
 end;
 
 
 function TPCJSONVariantValue.AsString(DefValue: String): String;
 function TPCJSONVariantValue.AsString(DefValue: String): String;
@@ -467,7 +479,7 @@ end;
 constructor TPCJSONVariantValue.CreateFromJSONValue(JSONValue: TJSONValue);
 constructor TPCJSONVariantValue.CreateFromJSONValue(JSONValue: TJSONValue);
 {$IFnDEF FPC}
 {$IFnDEF FPC}
 Var d : Double;
 Var d : Double;
-    i : Integer;
+    i64 : Integer;
   ds,ts : Char;
   ds,ts : Char;
 {$ENDIF}
 {$ENDIF}
 begin
 begin
@@ -477,15 +489,15 @@ begin
   {$ELSE}
   {$ELSE}
   if JSONValue is TJSONNumber then begin
   if JSONValue is TJSONNumber then begin
     d := TJSONNumber(JSONValue).AsDouble;
     d := TJSONNumber(JSONValue).AsDouble;
-    if Pos('.',JSONValue.ToString)>0 then i := 0
-    else i := TJSONNumber(JSONValue).AsInt;
+    if Pos('.',JSONValue.ToString)>0 then i64 := 0
+    else i64 := TJSONNumber(JSONValue).AsInt;
     ds := DecimalSeparator;
     ds := DecimalSeparator;
     ts := ThousandSeparator;
     ts := ThousandSeparator;
     DecimalSeparator := '.';
     DecimalSeparator := '.';
     ThousandSeparator := ',';
     ThousandSeparator := ',';
     Try
     Try
-      if FormatFloat('0.###########',d)=inttostr(i) then
-        Value := i
+      if FormatFloat('0.###########',d)=inttostr(i64) then
+        Value := i64
       else Value := d;
       else Value := d;
     Finally
     Finally
       DecimalSeparator := ds;
       DecimalSeparator := ds;
@@ -508,8 +520,8 @@ function TPCJSONVariantValue.ToJSONFormatted(pretty: Boolean; const prefix: Ansi
 Var   ds,ts : Char;
 Var   ds,ts : Char;
 begin
 begin
   Case VarType(Value) of
   Case VarType(Value) of
-    varSmallint,varInteger,varByte,varWord : Result := IntToStr(Value);
-    varLongWord,varInt64 : Result := IntToStr(Value);
+    varSmallint,varInteger,varByte,varWord,
+    varLongWord,varInt64 : Result := VarToStr(Value);
     varBoolean : if (Value) then Result := 'true' else Result:='false';
     varBoolean : if (Value) then Result := 'true' else Result:='false';
     varNull : Result := 'null';
     varNull : Result := 'null';
     varDate,varDouble : begin
     varDate,varDouble : begin
@@ -549,6 +561,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TPCJSONObject.AsCardinal(ParamName: String; DefValue: Cardinal): Cardinal;
+begin
+  Result := Cardinal(AsInt64(ParamName,DefValue));
+end;
+
 function TPCJSONObject.AsCurrency(ParamName: String; DefValue: Currency): Currency;
 function TPCJSONObject.AsCurrency(ParamName: String; DefValue: Currency): Currency;
 Var v : Variant;
 Var v : Variant;
   VV : TPCJSONVariantValue;
   VV : TPCJSONVariantValue;
@@ -604,6 +621,24 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TPCJSONObject.AsInt64(ParamName: String; DefValue: Int64): Int64;
+Var v : Variant;
+  VV : TPCJSONVariantValue;
+begin
+  VV := GetAsVariant(ParamName);
+  if (VarType(VV.Value)=varNull) AND (VarType( VV.FOldValue ) = varEmpty) then begin
+    Result := DefValue;
+    Exit;
+  end;
+  v := GetAsVariant(ParamName).Value;
+  try
+    if VarIsNull(v) then Result := DefValue
+    else Result := StrToInt64Def(VarToStrDef(v,''),DefValue);
+  except
+    Result := DefValue;
+  end;
+end;
+
 function TPCJSONObject.AsInteger(ParamName: String; DefValue: Integer): Integer;
 function TPCJSONObject.AsInteger(ParamName: String; DefValue: Integer): Integer;
 Var v : Variant;
 Var v : Variant;
   VV : TPCJSONVariantValue;
   VV : TPCJSONVariantValue;
@@ -616,7 +651,7 @@ begin
   v := GetAsVariant(ParamName).Value;
   v := GetAsVariant(ParamName).Value;
   try
   try
     if VarIsNull(v) then Result := DefValue
     if VarIsNull(v) then Result := DefValue
-    else Result := VarAsType(v,varInteger);
+    else Result := StrToIntDef(VarToStrDef(v,''),DefValue);
   except
   except
     Result := DefValue;
     Result := DefValue;
   end;
   end;
@@ -935,10 +970,10 @@ Var JS : TJSONValue;
   {$ENDIF}
   {$ENDIF}
 begin
 begin
   Result := Nil;
   Result := Nil;
+  JS := Nil;
   {$IFDEF FPC}
   {$IFDEF FPC}
   SetLength(jss,length(JSONObject));
   SetLength(jss,length(JSONObject));
   for i:=0 to High(JSONObject) do jss[i+1] := AnsiChar( JSONObject[i] );
   for i:=0 to High(JSONObject) do jss[i+1] := AnsiChar( JSONObject[i] );
-  JS := Nil;
   Try
   Try
     JS := GetJSON(jss);
     JS := GetJSON(jss);
   Except
   Except
@@ -947,7 +982,13 @@ begin
     end;
     end;
   end;
   end;
   {$ELSE}
   {$ELSE}
-  JS := TJSONObject.ParseJSONValue(JSONObject,0);
+  Try
+    JS := TJSONObject.ParseJSONValue(JSONObject,0);
+  Except
+    On E:Exception do begin
+      TLog.NewLog(ltDebug,ClassName,'Error processing JSON: '+E.Message);
+    end;
+  End;
   {$ENDIF}
   {$ENDIF}
   if Not Assigned(JS) then exit;
   if Not Assigned(JS) then exit;
   Try
   Try

+ 204 - 0
pascalcoin_daemon.pp

@@ -0,0 +1,204 @@
+program pascalcoin_daemon;
+
+{$mode objfpc}{$H+}
+{$define usecthreads}
+{$apptype gui}
+
+uses
+  {$IFDEF UNIX}{$IFDEF UseCThreads}
+  cthreads,
+  {$ENDIF}{$ENDIF}
+  sysutils,
+  Classes, daemonapp, 
+  SyncObjs,
+  UOpenSSL, UCrypto, UNode, UFileStorage, UFolderHelper, UWalletKeys, UConst, ULog, UNetProtocol,
+  URPC;
+
+Type
+
+  { TPCDaemonThread }
+
+  TPCDaemonThread = Class(TThread)
+    procedure OnPascalCoinLog(logtype : TLogType; Time : TDateTime; AThreadID : Cardinal; Const sender, logtext : AnsiString);
+    Procedure Execute; override;
+  end;
+
+  { TPCDaemon }
+
+  TPCDaemon = Class(TCustomDaemon)
+  Private
+    FThread : TPCDaemonThread;
+    Procedure ThreadStopped (Sender : TObject);
+  public
+    Function Start : Boolean; override;
+    Function Stop : Boolean; override;
+    Function Pause : Boolean; override;
+    Function Continue : Boolean; override;
+    Function Execute : Boolean; override;
+    Function ShutDown : Boolean; override;
+    Function Install : Boolean; override;
+    Function UnInstall: boolean; override;
+  end;
+
+{ TPCDaemonThread }
+
+procedure TPCDaemonThread.OnPascalCoinLog(logtype: TLogType; Time: TDateTime;
+  AThreadID: Cardinal; const sender, logtext: AnsiString);
+Var s : AnsiString;
+begin
+  if (logtype=ltdebug)  then exit;
+  if AThreadID=MainThreadID then s := ' MAIN:' else s:=' TID:';
+  WriteLn(formatDateTime('dd/mm/yyyy hh:nn:ss.zzz',Time)+s+IntToHex(AThreadID,8)+' ['+CT_LogType[Logtype]+'] <'+sender+'> '+logtext);
+end;
+
+Procedure AWriteln(MSg : String; B : Boolean);
+begin
+  Application.Log(etcustom,Msg+BoolToStr(B));
+end;
+
+procedure TPCDaemonThread.Execute;
+var
+  FNode : TNode;
+  FWalletKeys : TWalletKeysExt;
+  FRPC : TRPCServer;
+  FLog : TLog;
+begin
+  FLog := TLog.Create(Nil);
+  FLog.OnInThreadNewLog:=@OnPascalCoinLog;
+  try
+  FWalletKeys := TWalletKeysExt.Create(Nil);
+
+  TLog.NewLog(ltinfo,Classname,'PascalCoin Server');
+  // Load Node
+  // Check OpenSSL dll
+  if Not LoadSSLCrypt then raise Exception.Create('Cannot load '+SSL_C_LIB+#10+'To use this software make sure this file is available on you system or reinstall the application');
+  TCrypto.InitCrypto;
+  FWalletKeys.WalletFileName := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'WalletKeys.dat';
+  // Creating Node:
+  FNode := TNode.Node;
+  // RPC Server
+  FRPC := TRPCServer.Create;
+  FRPC.WalletKeys := FWalletKeys;
+  FRPC.Active:=true;
+  // Check Database
+  FNode.Bank.StorageClass := TFileStorage;
+  TFileStorage(FNode.Bank.Storage).DatabaseFolder := TFolderHelper.GetPascalCoinDataFolder+PathDelim+'Data';
+  // Reading database
+  FNode.Node.Bank.DiskRestoreFromOperations(CT_MaxBlock);
+  FWalletKeys.SafeBox := FNode.Node.Bank.SafeBox;
+  FNode.Node.AutoDiscoverNodes(CT_Discover_IPs);
+  FNode.Node.NetServer.Active := true;
+
+  Repeat
+    Sleep(100);
+  Until Terminated;
+
+
+
+  FreeAndNil(FRPC);
+  FNode.NetServer.Active := false;
+  TNetData.NetData.Free;
+  FreeAndNil(FNode);
+  except
+    on e:Exception do begin
+      TLog.NewLog(lterror,Classname,'Exception '+E.Classname+': '+E.Message);
+      AWriteln('Exception '+E.Classname+': '+E.Message,false);
+    end;
+  end;
+end;
+
+{ TPCDaemon }
+
+procedure TPCDaemon.ThreadStopped(Sender: TObject);
+begin
+  FreeAndNil(FThread);
+end;
+
+function TPCDaemon.Start: Boolean;
+begin
+  Result:=inherited Start;
+  AWriteln('Daemon Start',Result);
+  FThread:=TPCDaemonThread.Create(True);
+  FThread.OnTerminate:=@ThreadStopped;
+  FThread.FreeOnTerminate:=False;
+  FThread.Resume;
+end;
+
+function TPCDaemon.Stop: Boolean;
+begin
+  Result:=inherited Stop;
+  AWriteln('Daemon Stop: ',Result);
+  FThread.Terminate;
+end;
+
+function TPCDaemon.Pause: Boolean;
+begin
+  Result:=inherited Pause;
+  AWriteln('Daemon pause: ',Result);
+  FThread.Suspend;
+end;
+
+function TPCDaemon.Continue: Boolean;
+begin
+  Result:=inherited Continue;
+  AWriteln('Daemon continue: ',Result);
+  FThread.Resume;
+end;
+
+function TPCDaemon.Execute: Boolean;
+begin
+  Result:=inherited Execute;
+  AWriteln('Daemon execute: ',Result);
+end;
+
+function TPCDaemon.ShutDown: Boolean;
+begin
+  Result:=inherited ShutDown;
+  AWriteln('Daemon Shutdown: ',Result);
+  FThread.Terminate;
+end;
+
+function TPCDaemon.Install: Boolean;
+begin
+  Result:=inherited Install;
+  AWriteln('Daemon Install: ',Result);
+end;
+
+function TPCDaemon.UnInstall: boolean;
+begin
+  Result:=inherited UnInstall;
+  AWriteln('Daemon UnInstall: ',Result);
+end;
+
+Type
+
+  { TPCDaemonMapper }
+
+  TPCDaemonMapper = Class(TCustomDaemonMapper)
+    Constructor Create(AOwner : TComponent); override;
+  end;
+
+{ TPCDaemonMapper }
+
+constructor TPCDaemonMapper.Create(AOwner: TComponent);
+
+Var
+  D : TDaemonDef;
+
+begin
+  inherited Create(AOwner);
+  D:=DaemonDefs.Add as TDaemonDef;
+  D.DisplayName:='Pascal Coin Daemon';
+  D.Name:='PascalCoinDaemon';
+  D.DaemonClassName:='TPCDaemon';
+  D.WinBindings.ServiceType:=stWin32;
+end;
+
+begin
+  TCrypto.InitCrypto;
+  RegisterDaemonClass(TPCDaemon);
+  RegisterDaemonMapper(TPCDaemonMapper);
+  Application.Title:='Daemon application';
+  Application.Run;
+end.
+