Browse Source

Updating core with Node Mempool object using locking/unlocking

PascalCoin 6 years ago
parent
commit
6329dd0ddc
4 changed files with 100 additions and 74 deletions
  1. 5 2
      src/core/UBlockChain.pas
  2. 22 15
      src/core/UNetProtocol.pas
  3. 23 18
      src/core/UPoolMining.pas
  4. 50 39
      src/core/URPC.pas

+ 5 - 2
src/core/UBlockChain.pas

@@ -903,7 +903,7 @@ Var
   tc : TTickCount;
   tc : TTickCount;
   LBlocks : TList<TPCOperationsComp>;
   LBlocks : TList<TPCOperationsComp>;
   LTmpPCOperationsComp : TPCOperationsComp;
   LTmpPCOperationsComp : TPCOperationsComp;
-  i,j : Integer;
+  i,j, LProgressBlock, LProgressEndBlock : Integer;
   LSafeboxTransaction : TPCSafeBoxTransaction;
   LSafeboxTransaction : TPCSafeBoxTransaction;
 begin
 begin
   if FIsRestoringFromFile then begin
   if FIsRestoringFromFile then begin
@@ -933,6 +933,8 @@ begin
       NewLog(Nil, ltinfo,'Start restoring from disk operations (Max '+inttostr(max_block)+') BlockCount: '+inttostr(BlocksCount)+' Orphan: ' +Storage.Orphan);
       NewLog(Nil, ltinfo,'Start restoring from disk operations (Max '+inttostr(max_block)+') BlockCount: '+inttostr(BlocksCount)+' Orphan: ' +Storage.Orphan);
       LBlocks := TList<TPCOperationsComp>.Create;
       LBlocks := TList<TPCOperationsComp>.Create;
       try
       try
+        LProgressBlock := 0;
+        LProgressEndBlock := Storage.LastBlock - BlocksCount;
         while ((BlocksCount<=max_block)) do begin
         while ((BlocksCount<=max_block)) do begin
           i := BlocksCount;
           i := BlocksCount;
           j := i + 99;
           j := i + 99;
@@ -962,6 +964,7 @@ begin
             end;
             end;
 
 
             for i := 0 to LBlocks.Count-1 do begin
             for i := 0 to LBlocks.Count-1 do begin
+              inc(LProgressBlock);
               SetLength(errors,0);
               SetLength(errors,0);
               if Not AddNewBlockChainBlock(LBlocks[i],0,newBlock,errors) then begin
               if Not AddNewBlockChainBlock(LBlocks[i],0,newBlock,errors) then begin
                 NewLog(LBlocks[i], lterror,'Error restoring block: ' + Inttostr(BlocksCount)+ ' Errors: ' + errors);
                 NewLog(LBlocks[i], lterror,'Error restoring block: ' + Inttostr(BlocksCount)+ ' Errors: ' + errors);
@@ -975,7 +978,7 @@ begin
                 end;
                 end;
                 if (Assigned(restoreProgressNotify)) And (TPlatform.GetElapsedMilliseconds(tc)>1000) then begin
                 if (Assigned(restoreProgressNotify)) And (TPlatform.GetElapsedMilliseconds(tc)>1000) then begin
                   tc := TPlatform.GetTickCount;
                   tc := TPlatform.GetTickCount;
-                  restoreProgressNotify(Self,Format('Reading blockchain block %d/%d',[LBlocks[i].OperationBlock.block,Storage.LastBlock]),BlocksCount,Storage.LastBlock);
+                  restoreProgressNotify(Self,Format('Reading blockchain block %d/%d',[LBlocks[i].OperationBlock.block,Storage.LastBlock]),LProgressBlock,LProgressEndBlock);
                 end;
                 end;
               end;
               end;
             end;
             end;

+ 22 - 15
src/core/UNetProtocol.pas

@@ -3134,6 +3134,7 @@ var responseStream : TMemoryStream;
   DoDisconnect : Boolean;
   DoDisconnect : Boolean;
   errors : String;
   errors : String;
   opht : TOperationsHashTree;
   opht : TOperationsHashTree;
+  LLockedMempool : TPCOperationsComp;
 begin
 begin
   {
   {
   This call is used to obtain pending operations not included in blockchain
   This call is used to obtain pending operations not included in blockchain
@@ -3157,7 +3158,7 @@ begin
     DataBuffer.Read(b,1);
     DataBuffer.Read(b,1);
     if (b=1) then begin
     if (b=1) then begin
       // Return count
       // Return count
-      c := TNode.Node.Operations.Count;
+      c := TNode.Node.MempoolOperationsCount;
       responseStream.Write(c,SizeOf(c));
       responseStream.Write(c,SizeOf(c));
     end else if (b=2) then begin
     end else if (b=2) then begin
       // Return from start to start+max
       // Return from start to start+max
@@ -3172,17 +3173,17 @@ begin
       end;
       end;
       opht := TOperationsHashTree.Create;
       opht := TOperationsHashTree.Create;
       Try
       Try
-        TNode.Node.Operations.Lock;
+        LLockedMempool := TNode.Node.LockMempoolRead;
         Try
         Try
-          if (start >= TNode.Node.Operations.Count) Or (max=0) then begin
+          if (start >= LLockedMempool.Count) Or (max=0) then begin
           end else begin
           end else begin
-            if (start + max >= TNode.Node.Operations.Count) then max := TNode.Node.Operations.Count - start;
+            if (start + max >= LLockedMempool.Count) then max := LLockedMempool.Count - start;
             for i:=start to (start + max -1) do begin
             for i:=start to (start + max -1) do begin
-              opht.AddOperationToHashTree(TNode.Node.Operations.OperationsHashTree.GetOperation(i));
+              opht.AddOperationToHashTree(LLockedMempool.OperationsHashTree.GetOperation(i));
             end;
             end;
           end;
           end;
         finally
         finally
-          TNode.Node.Operations.Unlock;
+          TNode.Node.UnlockMempoolRead;
         end;
         end;
         opht.SaveOperationsHashTreeToStream(responseStream,False);
         opht.SaveOperationsHashTreeToStream(responseStream,False);
       Finally
       Finally
@@ -3337,7 +3338,7 @@ begin
       if (iPubKey>=0) then begin
       if (iPubKey>=0) then begin
         ocl := sbakl.AccountKeyList[iPubKey];
         ocl := sbakl.AccountKeyList[iPubKey];
         while (start<ocl.Count) And (max>0) do begin
         while (start<ocl.Count) And (max>0) do begin
-          acc := TNode.Node.Operations.SafeBoxTransaction.Account(ocl.Get(start));
+          acc := TNode.Node.GetMempoolAccount(ocl.Get(start));
           TAccountComp.SaveAccountToAStream(accountsStream,acc);
           TAccountComp.SaveAccountToAStream(accountsStream,acc);
           inc(nAccounts);
           inc(nAccounts);
           inc(start);
           inc(start);
@@ -3435,7 +3436,7 @@ begin
         c := max;
         c := max;
         responseStream.Write(c,SizeOf(c));
         responseStream.Write(c,SizeOf(c));
         for i:=start to (start + max -1) do begin
         for i:=start to (start + max -1) do begin
-          acc := TNode.Node.Operations.SafeBoxTransaction.Account(i);
+          acc := TNode.Node.GetMempoolAccount(i);
           TAccountComp.SaveAccountToAStream(responseStream,acc);
           TAccountComp.SaveAccountToAStream(responseStream,acc);
         end;
         end;
       end;
       end;
@@ -3447,7 +3448,7 @@ begin
       for i:=1 to max do begin
       for i:=1 to max do begin
         DataBuffer.Read(c,SizeOf(c));
         DataBuffer.Read(c,SizeOf(c));
         if (c>=0) And (c<TNode.Node.Bank.AccountsCount) then begin
         if (c>=0) And (c<TNode.Node.Bank.AccountsCount) then begin
-          acc := TNode.Node.Operations.SafeBoxTransaction.Account(c);
+          acc := TNode.Node.GetMempoolAccount(c);
           TAccountComp.SaveAccountToAStream(responseStream,acc);
           TAccountComp.SaveAccountToAStream(responseStream,acc);
         end else begin
         end else begin
           errors := 'Invalid account number '+Inttostr(c);
           errors := 'Invalid account number '+Inttostr(c);
@@ -3669,6 +3670,7 @@ var operationsComp : TPCOperationsComp;
     auxOp : TPCOperation;
     auxOp : TPCOperation;
     tc : TTickCount;
     tc : TTickCount;
     original_OperationBlock : TOperationBlock;
     original_OperationBlock : TOperationBlock;
+    LLockedMempool : TPCOperationsComp;
   begin
   begin
     Result := False;
     Result := False;
     DoDisconnect := True;
     DoDisconnect := True;
@@ -3694,13 +3696,18 @@ var operationsComp : TPCOperationsComp;
       Try
       Try
         if (operationsComp.OperationBlock.block<>TNode.Node.Bank.BlocksCount) then Exit; // Meanwhile other threads have added it
         if (operationsComp.OperationBlock.block<>TNode.Node.Bank.BlocksCount) then Exit; // Meanwhile other threads have added it
         // Fill not included operations:
         // Fill not included operations:
-        for i:=0 to High(nfpboarr) do begin
-          iNodeOpReference := TNode.Node.Operations.OperationsHashTree.IndexOfOpReference(nfpboarr[i].opReference);
-          if iNodeOpReference>=0 then begin
-            nfpboarr[i].opStreamData := TNode.Node.Operations.OperationsHashTree.GetOperation(iNodeOpReference).GetOperationStreamData;
-          end else begin
-            inc(notFoundOpReferencesCount);
+        LLockedMempool := TNode.Node.LockMempoolRead;
+        try
+          for i:=0 to High(nfpboarr) do begin
+            iNodeOpReference := LLockedMempool.OperationsHashTree.IndexOfOpReference(nfpboarr[i].opReference);
+            if iNodeOpReference>=0 then begin
+              nfpboarr[i].opStreamData := LLockedMempool.OperationsHashTree.GetOperation(iNodeOpReference).GetOperationStreamData;
+            end else begin
+              inc(notFoundOpReferencesCount);
+            end;
           end;
           end;
+        finally
+          TNode.Node.UnlockMempoolRead;
         end;
         end;
       Finally
       Finally
         TNode.Node.UnlockNode;
         TNode.Node.UnlockNode;

+ 23 - 18
src/core/UPoolMining.pas

@@ -520,6 +520,7 @@ Var P, PToDelete : PPoolJob;
   doAdd : Boolean;
   doAdd : Boolean;
   params : TPCJSONObject;
   params : TPCJSONObject;
   OpB : TOperationBlock;
   OpB : TOperationBlock;
+  LLockedMempool : TPCOperationsComp;
 begin
 begin
   if Not Active then exit;
   if Not Active then exit;
   if FClientsCount<=0 then exit;
   if FClientsCount<=0 then exit;
@@ -530,11 +531,16 @@ begin
     if l.count=0 then doAdd := true
     if l.count=0 then doAdd := true
     else begin
     else begin
       P := l[l.Count-1];
       P := l[l.Count-1];
-      if (FNodeNotifyEvents.Node.Operations.OperationsHashTree.HashTree<>P^.OperationsComp.OperationsHashTree.HashTree) then begin
-        doAdd := (P^.SentDateTime + EncodeTime(0,0,CT_WAIT_SECONDS_BEFORE_SEND_NEW_JOB,0)) < Now;
-      end else begin
-        // No new operations waiting to be sent, but to prevent "old time mining", we will send new job with time:
-        doAdd := ((P^.SentDateTime + EncodeTime(0,0,CT_MAX_SECONDS_BETWEEN_JOBS,0)) < Now);
+      LLockedMempool := FNodeNotifyEvents.Node.LockMempoolRead;
+      try
+        if (Not TBaseType.Equals(LLockedMempool.OperationsHashTree.HashTree,P^.OperationsComp.OperationsHashTree.HashTree)) then begin
+          doAdd := (P^.SentDateTime + EncodeTime(0,0,CT_WAIT_SECONDS_BEFORE_SEND_NEW_JOB,0)) < Now;
+        end else begin
+          // No new operations waiting to be sent, but to prevent "old time mining", we will send new job with time:
+          doAdd := ((P^.SentDateTime + EncodeTime(0,0,CT_MAX_SECONDS_BETWEEN_JOBS,0)) < Now);
+        end;
+      finally
+        FNodeNotifyEvents.Node.UnlockMempoolRead;
       end;
       end;
     end;
     end;
     if doAdd then begin
     if doAdd then begin
@@ -712,24 +718,23 @@ var tree : TOperationsHashTree;
     tree.AddOperationToHashTree(Op);
     tree.AddOperationToHashTree(Op);
   End;
   End;
 Var i,j : Integer;
 Var i,j : Integer;
-  MasterOp : TPCOperationsComp;
+  LLockedMempool : TPCOperationsComp;
   op : TPCOperation;
   op : TPCOperation;
   errors : String;
   errors : String;
 begin
 begin
-  MasterOp := FNodeNotifyEvents.Node.Operations;
-  MasterOp.Lock;
+  LLockedMempool := FNodeNotifyEvents.Node.LockMempoolRead;
   Try
   Try
     FMinerOperations.Lock;
     FMinerOperations.Lock;
     Try
     Try
       tree := TOperationsHashTree.Create;
       tree := TOperationsHashTree.Create;
       try
       try
-        if (Not (TPCOperationsComp.EqualsOperationBlock(FMinerOperations.OperationBlock,MasterOp.OperationBlock))) then begin
+        if (Not (TPCOperationsComp.EqualsOperationBlock(FMinerOperations.OperationBlock,LLockedMempool.OperationBlock))) then begin
           FMinerOperations.Clear(true);
           FMinerOperations.Clear(true);
-          if MasterOp.Count>0 then begin
+          if LLockedMempool.Count>0 then begin
             // First round: Select with fee > 0
             // First round: Select with fee > 0
             i := 0;
             i := 0;
-            while (tree.OperationsCount<MaxOperationsPerBlock) And (i<MasterOp.OperationsHashTree.OperationsCount) do begin
-              op := MasterOp.OperationsHashTree.GetOperation(i);
+            while (tree.OperationsCount<MaxOperationsPerBlock) And (i<LLockedMempool.OperationsHashTree.OperationsCount) do begin
+              op := LLockedMempool.OperationsHashTree.GetOperation(i);
               if op.OperationFee>0 then begin
               if op.OperationFee>0 then begin
                 DoAdd(op,false);
                 DoAdd(op,false);
               end;
               end;
@@ -738,8 +743,8 @@ begin
             // Second round: Allow fee = 0
             // Second round: Allow fee = 0
             j := 0;
             j := 0;
             i := 0;
             i := 0;
-            while (tree.OperationsCount<MaxOperationsPerBlock) And (i<MasterOp.OperationsHashTree.OperationsCount) And (j<Max0FeeOperationsPerBlock) do begin
-              op := MasterOp.OperationsHashTree.GetOperation(i);
+            while (tree.OperationsCount<MaxOperationsPerBlock) And (i<LLockedMempool.OperationsHashTree.OperationsCount) And (j<Max0FeeOperationsPerBlock) do begin
+              op := LLockedMempool.OperationsHashTree.GetOperation(i);
               if op.OperationFee=0 then begin
               if op.OperationFee=0 then begin
                 DoAdd(op,True);
                 DoAdd(op,True);
                 inc(j);
                 inc(j);
@@ -748,12 +753,12 @@ begin
             end;
             end;
             // Add operations:
             // Add operations:
             i := FMinerOperations.AddOperations(tree,errors);
             i := FMinerOperations.AddOperations(tree,errors);
-            if (i<>tree.OperationsCount) Or (i<>MasterOp.OperationsHashTree.OperationsCount) then begin
+            if (i<>tree.OperationsCount) Or (i<>LLockedMempool.OperationsHashTree.OperationsCount) then begin
               TLog.NewLog(ltDebug,ClassName,Format('Cannot add all operations! Master:%d Selected:%d Added:%d - Errors: %s',
               TLog.NewLog(ltDebug,ClassName,Format('Cannot add all operations! Master:%d Selected:%d Added:%d - Errors: %s',
-                [MasterOp.OperationsHashTree.OperationsCount,tree.OperationsCount,i,errors]));
+                [LLockedMempool.OperationsHashTree.OperationsCount,tree.OperationsCount,i,errors]));
             end;
             end;
           end else begin
           end else begin
-            FMinerOperations.CopyFrom(MasterOp);
+            FMinerOperations.CopyFrom(LLockedMempool);
           end;
           end;
           //
           //
           TLog.NewLog(ltInfo,ClassName,Format('New miner operations:%d Hash:%s %s',
           TLog.NewLog(ltInfo,ClassName,Format('New miner operations:%d Hash:%s %s',
@@ -768,7 +773,7 @@ begin
       FMinerOperations.Unlock;
       FMinerOperations.Unlock;
     end;
     end;
   Finally
   Finally
-    MasterOp.Unlock;
+    FNodeNotifyEvents.Node.UnlockMempoolRead;
   End;
   End;
 end;
 end;
 
 

+ 50 - 39
src/core/URPC.pas

@@ -794,6 +794,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     Obj : TPCJSONObject;
     Obj : TPCJSONObject;
     OperationsResume : TOperationsResumeList;
     OperationsResume : TOperationsResumeList;
     i, nCounter : Integer;
     i, nCounter : Integer;
+    LLockedMempool : TPCOperationsComp;
   Begin
   Begin
     Result := false;
     Result := false;
     if (startReg<-1) or (maxReg<=0) then begin
     if (startReg<-1) or (maxReg<=0) then begin
@@ -809,18 +810,23 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         // Only will return pending operations if start=0, otherwise
         // Only will return pending operations if start=0, otherwise
         list := TList<Cardinal>.Create;
         list := TList<Cardinal>.Create;
         Try
         Try
-          FNode.Operations.OperationsHashTree.GetOperationsAffectingAccount(accountNumber,list);
-          for i := list.Count - 1 downto 0 do begin
-            Op := FNode.Operations.OperationsHashTree.GetOperation(PtrInt(list[i]));
-            If TPCOperation.OperationToOperationResume(0,Op,False,accountNumber,OPR) then begin
-              OPR.NOpInsideBlock := i;
-              OPR.Block := FNode.Operations.OperationBlock.block;
-              OPR.Balance := FNode.Operations.SafeBoxTransaction.Account(accountNumber).balance;
-              if (nCounter>=startReg) And (nCounter<maxReg) then begin
-                OperationsResume.Add(OPR);
+          LLockedMempool := FNode.LockMempoolRead;
+          try
+            LLockedMempool.OperationsHashTree.GetOperationsAffectingAccount(accountNumber,list);
+            for i := list.Count - 1 downto 0 do begin
+              Op := LLockedMempool.OperationsHashTree.GetOperation(list[i]);
+              If TPCOperation.OperationToOperationResume(0,Op,False,accountNumber,OPR) then begin
+                OPR.NOpInsideBlock := i;
+                OPR.Block := LLockedMempool.OperationBlock.block;
+                OPR.Balance := LLockedMempool.SafeBoxTransaction.Account(accountNumber).balance;
+                if (nCounter>=startReg) And (nCounter<maxReg) then begin
+                  OperationsResume.Add(OPR);
+                end;
+                inc(nCounter);
               end;
               end;
-              inc(nCounter);
             end;
             end;
+          finally
+            FNode.UnlockMempoolRead;
           end;
           end;
         Finally
         Finally
           list.Free;
           list.Free;
@@ -993,8 +999,8 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
         ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
         Exit;
         Exit;
       end;
       end;
-      sacc := FNode.Operations.SafeBoxTransaction.Account(sender);
-      tacc := FNode.Operations.SafeBoxTransaction.Account(target);
+      sacc := FNode.GetMempoolAccount(sender);
+      tacc := FNode.GetMempoolAccount(target);
 
 
       opt := CreateOperationTransaction(FNode.Bank.SafeBox.CurrentProtocol,sender,target,sacc.n_operation,amount,fee,sacc.accountInfo.accountKey,tacc.accountInfo.accountKey,RawPayload,Payload_method,EncodePwd);
       opt := CreateOperationTransaction(FNode.Bank.SafeBox.CurrentProtocol,sender,target,sacc.n_operation,amount,fee,sacc.accountInfo.accountKey,tacc.accountInfo.accountKey,RawPayload,Payload_method,EncodePwd);
       if opt=nil then exit;
       if opt=nil then exit;
@@ -1086,7 +1092,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
         ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
         ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
         Exit;
         Exit;
       end;
       end;
-      acc_signer := FNode.Operations.SafeBoxTransaction.Account(account_signer);
+      acc_signer := FNode.GetMempoolAccount(account_signer);
 
 
       opck := CreateOperationChangeKey(FNode.Bank.SafeBox.CurrentProtocol,account_signer,acc_signer.n_operation,account_target,acc_signer.accountInfo.accountKey,new_pub_key,fee,RawPayload,Payload_method,EncodePwd);
       opck := CreateOperationChangeKey(FNode.Bank.SafeBox.CurrentProtocol,account_signer,acc_signer.n_operation,account_target,acc_signer.accountInfo.accountKey,new_pub_key,fee,RawPayload,Payload_method,EncodePwd);
       if not assigned(opck) then exit;
       if not assigned(opck) then exit;
@@ -1253,7 +1259,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
               ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
               ErrorNum:=CT_RPC_ErrNum_InvalidAccount;
               Exit;
               Exit;
             end;
             end;
-            acc := FNode.Operations.SafeBoxTransaction.Account(accountsnumber.Get(ian));
+            acc := FNode.GetMempoolAccount(accountsnumber.Get(ian));
             opck := CreateOperationChangeKey(FNode.Bank.SafeBox.CurrentProtocol,acc.account,acc.n_operation,acc.account,acc.accountInfo.accountKey,new_pub_key,fee,RawPayload,Payload_method,EncodePwd);
             opck := CreateOperationChangeKey(FNode.Bank.SafeBox.CurrentProtocol,acc.account,acc.n_operation,acc.account,acc.accountInfo.accountKey,new_pub_key,fee,RawPayload,Payload_method,EncodePwd);
             if not assigned(opck) then exit;
             if not assigned(opck) then exit;
             try
             try
@@ -1923,7 +1929,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := 'Invalid account_signer '+params.AsString('account_signer','');
           ErrorDesc := 'Invalid account_signer '+params.AsString('account_signer','');
           Exit;
           Exit;
         end;
         end;
-        account_signer := FNode.Operations.SafeBoxTransaction.Account(c_account);
+        account_signer := FNode.GetMempoolAccount(c_account);
         if (params.IndexOfName('account_target')<0) then begin
         if (params.IndexOfName('account_target')<0) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorDesc := 'Need account_target param';
           ErrorDesc := 'Need account_target param';
@@ -1935,7 +1941,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := 'Invalid account_target '+params.AsString('account_target','');
           ErrorDesc := 'Invalid account_target '+params.AsString('account_target','');
           Exit;
           Exit;
         end;
         end;
-        account_target := FNode.Operations.SafeBoxTransaction.Account(c_account);
+        account_target := FNode.GetMempoolAccount(c_account);
         if (Not TAccountComp.EqualAccountKeys(account_signer.accountInfo.accountKey,account_target.accountInfo.accountKey)) then begin
         if (Not TAccountComp.EqualAccountKeys(account_signer.accountInfo.accountKey,account_target.accountInfo.accountKey)) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorDesc := 'account_signer and account_target have distinct keys. Cannot sign';
           ErrorDesc := 'account_signer and account_target have distinct keys. Cannot sign';
@@ -1982,7 +1988,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := 'Invalid account_signer '+params.AsString('account_signer','');
           ErrorDesc := 'Invalid account_signer '+params.AsString('account_signer','');
           Exit;
           Exit;
         end;
         end;
-        account_signer := FNode.Operations.SafeBoxTransaction.Account(c_account);
+        account_signer := FNode.GetMempoolAccount(c_account);
         if (params.IndexOfName('account_target')<0) then begin
         if (params.IndexOfName('account_target')<0) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorDesc := 'Need account_target param';
           ErrorDesc := 'Need account_target param';
@@ -1994,7 +2000,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := 'Invalid account_target '+params.AsString('account_target','');
           ErrorDesc := 'Invalid account_target '+params.AsString('account_target','');
           Exit;
           Exit;
         end;
         end;
-        account_target := FNode.Operations.SafeBoxTransaction.Account(c_account);
+        account_target := FNode.GetMempoolAccount(c_account);
         if (Not TAccountComp.EqualAccountKeys(account_signer.accountInfo.accountKey,account_target.accountInfo.accountKey)) then begin
         if (Not TAccountComp.EqualAccountKeys(account_signer.accountInfo.accountKey,account_target.accountInfo.accountKey)) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorDesc := 'account_signer and account_target have distinct keys. Cannot sign';
           ErrorDesc := 'account_signer and account_target have distinct keys. Cannot sign';
@@ -2041,7 +2047,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := 'Invalid account '+params.AsString('buyer_account','');
           ErrorDesc := 'Invalid account '+params.AsString('buyer_account','');
           Exit;
           Exit;
         end;
         end;
-        buyer_account := FNode.Operations.SafeBoxTransaction.Account(c_account);
+        buyer_account := FNode.GetMempoolAccount(c_account);
         // Check params
         // Check params
         c_account := params.AsInteger('account_to_purchase',MaxInt);
         c_account := params.AsInteger('account_to_purchase',MaxInt);
         if (c_account<0) or (c_account>=FNode.Bank.AccountsCount) then begin
         if (c_account<0) or (c_account>=FNode.Bank.AccountsCount) then begin
@@ -2049,7 +2055,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := 'Invalid account to purchase '+params.AsString('account_to_purchase','');
           ErrorDesc := 'Invalid account to purchase '+params.AsString('account_to_purchase','');
           Exit;
           Exit;
         end;
         end;
-        account_to_purchase := FNode.Operations.SafeBoxTransaction.Account(c_account);
+        account_to_purchase := FNode.GetMempoolAccount(c_account);
         if Not TAccountComp.IsAccountForSale(account_to_purchase.accountInfo) then begin
         if Not TAccountComp.IsAccountForSale(account_to_purchase.accountInfo) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorDesc := 'Account is not for sale: '+params.AsString('account_to_purchase','');
           ErrorDesc := 'Account is not for sale: '+params.AsString('account_to_purchase','');
@@ -2101,7 +2107,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := 'Invalid account_signer '+params.AsString('account_signer','');
           ErrorDesc := 'Invalid account_signer '+params.AsString('account_signer','');
           Exit;
           Exit;
         end;
         end;
-        account_signer := FNode.Operations.SafeBoxTransaction.Account(c_account);
+        account_signer := FNode.GetMempoolAccount(c_account);
         if (params.IndexOfName('account_target')<0) then begin
         if (params.IndexOfName('account_target')<0) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorDesc := 'Need account_target param';
           ErrorDesc := 'Need account_target param';
@@ -2113,7 +2119,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           ErrorDesc := 'Invalid account_target '+params.AsString('account_target','');
           ErrorDesc := 'Invalid account_target '+params.AsString('account_target','');
           Exit;
           Exit;
         end;
         end;
-        account_target := FNode.Operations.SafeBoxTransaction.Account(c_account);
+        account_target := FNode.GetMempoolAccount(c_account);
         if (Not TAccountComp.EqualAccountKeys(account_signer.accountInfo.accountKey,account_target.accountInfo.accountKey)) then begin
         if (Not TAccountComp.EqualAccountKeys(account_signer.accountInfo.accountKey,account_target.accountInfo.accountKey)) then begin
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorNum := CT_RPC_ErrNum_InvalidAccount;
           ErrorDesc := 'account_signer and account_target have distinct keys. Cannot sign';
           ErrorDesc := 'account_signer and account_target have distinct keys. Cannot sign';
@@ -2205,7 +2211,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     if ((Length(accountName)>0) AND (exactMatch=true)) then begin
     if ((Length(accountName)>0) AND (exactMatch=true)) then begin
        accountNumber := FNode.Bank.SafeBox.FindAccountByName(accountName);
        accountNumber := FNode.Bank.SafeBox.FindAccountByName(accountName);
        if accountNumber >= 0 then begin
        if accountNumber >= 0 then begin
-          account := FNode.Operations.SafeBoxTransaction.Account(accountNumber);
+          account := FNode.GetMempoolAccount(accountNumber);
           if ((accountType = -1) OR (Integer(account.account_type) = accountType))
           if ((accountType = -1) OR (Integer(account.account_type) = accountType))
              AND
              AND
              ((Not searchByPubkey) OR (TAccountComp.EqualAccountKeys(accPubKey,account.accountInfo.accountKey))) then
              ((Not searchByPubkey) OR (TAccountComp.EqualAccountKeys(accPubKey,account.accountInfo.accountKey))) then
@@ -2216,9 +2222,9 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
       for i := start to FNode.Bank.AccountsCount - 1 do begin
       for i := start to FNode.Bank.AccountsCount - 1 do begin
         if (searchByPubkey) then begin
         if (searchByPubkey) then begin
           if (i>=FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[iPubKey].Count) then Break;
           if (i>=FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[iPubKey].Count) then Break;
-          account := FNode.Operations.SafeBoxTransaction.Account( FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[iPubKey].Get(i) );
+          account := FNode.GetMempoolAccount( FNode.Bank.SafeBox.OrderedAccountKeysList.AccountKeyList[iPubKey].Get(i) );
         end else begin
         end else begin
-          account := FNode.Operations.SafeBoxTransaction.Account(i);
+          account := FNode.GetMempoolAccount(i);
         end;
         end;
         if (accountType <> -1) AND (Integer(account.account_type) <> accountType) then
         if (accountType <> -1) AND (Integer(account.account_type) <> accountType) then
         begin
         begin
@@ -2302,7 +2308,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
     Begin
     Begin
       Result := CT_Account_NUL;
       Result := CT_Account_NUL;
       if (nAccount<0) Or (nAccount>=FNode.Bank.AccountsCount) then Exit;
       if (nAccount<0) Or (nAccount>=FNode.Bank.AccountsCount) then Exit;
-      Result := FNode.Operations.SafeBoxTransaction.Account( nAccount );
+      Result := FNode.GetMempoolAccount( nAccount );
     end;
     end;
 
 
   var errors : String;
   var errors : String;
@@ -2600,7 +2606,7 @@ function TRPCProcess.ProcessMethod(const method: String; params: TPCJSONObject;
           nAccount := PtrInt(lSigners[j]);
           nAccount := PtrInt(lSigners[j]);
           if (nAccount>=0) And (nAccount<FNode.Bank.AccountsCount) then begin
           if (nAccount>=0) And (nAccount<FNode.Bank.AccountsCount) then begin
             // Try to
             // Try to
-            pubKey := FNode.Operations.SafeBoxTransaction.Account(nAccount).accountInfo.accountKey;
+            pubKey := FNode.GetMempoolAccount(nAccount).accountInfo.accountKey;
             // Is mine?
             // Is mine?
             iKey := _RPCServer.FWalletKeys.IndexOfAccountKey(pubKey);
             iKey := _RPCServer.FWalletKeys.IndexOfAccountKey(pubKey);
             if (iKey>=0) then begin
             if (iKey>=0) then begin
@@ -2688,7 +2694,7 @@ begin
     // Returns JSON Object with account information based on BlockChain + Pending operations
     // Returns JSON Object with account information based on BlockChain + Pending operations
     c := params.GetAsVariant('account').AsCardinal(CT_MaxAccount);
     c := params.GetAsVariant('account').AsCardinal(CT_MaxAccount);
     if (c>=0) And (c<FNode.Bank.AccountsCount) then begin
     if (c>=0) And (c<FNode.Bank.AccountsCount) then begin
-      account := FNode.Operations.SafeBoxTransaction.Account(c);
+      account := FNode.GetMempoolAccount(c);
       TPascalCoinJSONComp.FillAccountObject(account,GetResultObject);
       TPascalCoinJSONComp.FillAccountObject(account,GetResultObject);
       Result := True;
       Result := True;
     end else begin
     end else begin
@@ -2723,7 +2729,7 @@ begin
       l := params.AsInteger('start',0);
       l := params.AsInteger('start',0);
       for j := 0 to ocl.Count - 1 do begin
       for j := 0 to ocl.Count - 1 do begin
         if (j>=l) then begin
         if (j>=l) then begin
-          account := FNode.Operations.SafeBoxTransaction.Account(ocl.Get(j));
+          account := FNode.GetMempoolAccount(ocl.Get(j));
           TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
           TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
         end;
         end;
         if (k>0) And ((j+1)>=(k+l)) then break;
         if (k>0) And ((j+1)>=(k+l)) then break;
@@ -2737,7 +2743,7 @@ begin
         ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
         ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
         for j := 0 to ocl.Count - 1 do begin
         for j := 0 to ocl.Count - 1 do begin
           if (c>=l) then begin
           if (c>=l) then begin
-            account := FNode.Operations.SafeBoxTransaction.Account(ocl.Get(j));
+            account := FNode.GetMempoolAccount(ocl.Get(j));
             TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
             TPascalCoinJSONComp.FillAccountObject(account,jsonarr.GetAsObject(jsonarr.Count));
           end;
           end;
           inc(c);
           inc(c);
@@ -2799,7 +2805,7 @@ begin
       ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
       ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
       account.balance := 0;
       account.balance := 0;
       for j := 0 to ocl.Count - 1 do begin
       for j := 0 to ocl.Count - 1 do begin
-        inc(account.balance, FNode.Operations.SafeBoxTransaction.Account(ocl.Get(j)).balance );
+        inc(account.balance, FNode.GetMempoolAccount(ocl.Get(j)).balance );
       end;
       end;
       jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
       jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
       Result := true;
       Result := true;
@@ -2810,7 +2816,7 @@ begin
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
       for i:=0 to _RPCServer.WalletKeys.AccountsKeyList.Count-1 do begin
         ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
         ocl := _RPCServer.WalletKeys.AccountsKeyList.AccountKeyList[i];
         for j := 0 to ocl.Count - 1 do begin
         for j := 0 to ocl.Count - 1 do begin
-          inc(account.balance, FNode.Operations.SafeBoxTransaction.Account(ocl.Get(j)).balance );
+          inc(account.balance, FNode.GetMempoolAccount(ocl.Get(j)).balance );
         end;
         end;
       end;
       end;
       jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
       jsonresponse.GetAsVariant('result').value := ToJSONCurrency(account.balance);
@@ -3012,13 +3018,18 @@ begin
     If FNode.TryLockNode(5000) then begin
     If FNode.TryLockNode(5000) then begin
       Try
       Try
         jsonarr := GetResultArray;
         jsonarr := GetResultArray;
-        for i := j to FNode.Operations.Count-1 do begin
-          If TPCOperation.OperationToOperationResume(0,FNode.Operations.Operation[i],True,FNode.Operations.Operation[i].SignerAccount,opr) then begin
-            opr.NOpInsideBlock:=i;
-            opr.Balance := -1; // Don't include!
-            FillOperationResumeToJSONObject(opr,jsonarr.GetAsObject(jsonarr.Count));
+        pcops := FNode.LockMempoolRead;
+        try
+          for i := j to pcops.Count-1 do begin
+            If TPCOperation.OperationToOperationResume(0,pcops.Operation[i],True,pcops.Operation[i].SignerAccount,opr) then begin
+              opr.NOpInsideBlock:=i;
+              opr.Balance := -1; // Don't include!
+              FillOperationResumeToJSONObject(opr,jsonarr.GetAsObject(jsonarr.Count));
+            end;
+            if (k>0) And (jsonarr.Count>=k) then break;
           end;
           end;
-          if (k>0) And (jsonarr.Count>=k) then break;
+        finally
+          FNode.UnlockMempoolRead;
         end;
         end;
       finally
       finally
         FNode.UnlockNode;
         FNode.UnlockNode;
@@ -3029,7 +3040,7 @@ begin
       ErrorDesc := 'Node is busy';
       ErrorDesc := 'Node is busy';
     end;
     end;
   end else if (method='getpendingscount') then begin
   end else if (method='getpendingscount') then begin
-    jsonresponse.GetAsVariant('result').Value := FNode.Operations.Count;
+    jsonresponse.GetAsVariant('result').Value := FNode.MempoolOperationsCount;
     Result := true;
     Result := true;
   end else if (method='decodeophash') then begin
   end else if (method='decodeophash') then begin
     // Search for an operation based on "ophash"
     // Search for an operation based on "ophash"