Browse Source

Merge pull request #218 from PascalCoin/master

Update with latest improvements
Albert Molina 3 years ago
parent
commit
e9e70ac3b9
8 changed files with 278 additions and 9 deletions
  1. 2 0
      .gitignore
  2. 2 2
      PIP/PIP-0027.md
  3. 152 0
      PIP/PIP-0042.md
  4. 1 0
      PIP/README.md
  5. 26 0
      src/core/UAccounts.pas
  6. 41 0
      src/core/UBlockChain.pas
  7. 44 1
      src/core/UPoolMining.pas
  8. 10 6
      src/pascalcoin_wallet_classic.lpi

+ 2 - 0
.gitignore

@@ -53,3 +53,5 @@ dunit.ini
 /PIP/resources/*.DS_Store
 /PIP/resources/PIP-0034A/*.DS_Store
 /src/*.tvsconfig
+src/libssl-1_1.dll
+src/libssl-1_1-x64.dll

+ 2 - 2
PIP/PIP-0027.md

@@ -636,6 +636,6 @@ A recursive-descent implementation can be found [here][2].
 1. [C# Regex Parser][1]
 2. [C# Recursive-Descent Parser][2]
 
-[1]: https://github.com/Sphere10/NPascalCoin/blob/master/src/NPascalCoin/Common/Text/RegexEPasaParser.cs
-[2]: https://github.com/Sphere10/NPascalCoin/blob/master/src/NPascalCoin/Common/Text/RecursiveDescentEPasaParser.cs
+[1]: https://github.com/Sphere10/NPascalCoin/blob/master/src/NPascalCoin/Encoding/RegexEPasaParser.cs
+[2]: https://github.com/Sphere10/NPascalCoin/blob/master/src/NPascalCoin/Encoding/RecursiveDescentEPasaParser.cs
 

+ 152 - 0
PIP/PIP-0042.md

@@ -0,0 +1,152 @@
+<pre>
+  PIP: PIP-0042
+  Title: Update OP_RECOVER to initial sense described on original WhitePaper and allow ASK FOR PASA feature
+  Type: Protocol
+  Impact: Hard-Fork
+  Author: Albert Molina <[email protected]>  
+  Copyright: Albert Molina, 2021 (All Rights Reserved)
+  Comments-URI: https://discord.gg/gamPX9E4RF (Discord channel #pip-42)
+  Status: Proposed
+  Created: 2021-09-23
+</pre>
+
+## Summary
+
+Update current OP_RECOVER operation in order to have a similar sense as described on [Original PascalCoin WhitePaper published on July 2016][1] few weeks before Genesis Block. 
+
+## Motivation
+
+OP_RECOVER feature was defined on original PascalCoin Whitepaper published on July 2016 as a way to allow recover coins that has lost private key. 
+
+**PascalCoin WhitePaper:** 
+```
+PascalCoin proposes an alternative to the basic operation of Bitcoin, through which change
+several aspects for working on the new virtual currency:
+...
+  - PascalCoin provides a method set by protocol to retrieve coins that are not used
+    instead (lost key). This method only applies if after a certain time the owner does not
+    make any operation with the account private key.
+...
+(Page 2/8)
+```
+
+Basically was a way to mantain a constant and predectible inflation and available coin because burning coins are not possible. 
+
+Current problem is that WhitePaper definition is ambiguous and **certain time** was not specified, initial source code proposal was to **set a time value = 4 years** (420480 blocks in PascalCoin) 
+
+Another problem is that WhitePaper didn't specified who can retrieve coins that are not used, neither what to do with Pascal Accounts (aka **PASA**) not used. 
+
+## Proposal
+
+This PIP specifies a more accurated OP_RECOVER feature that will mantain initial sense and will allow a fair PASA and coins distribution. 
+
+Update current OP_RECOVER to work as this: 
+
+1. The way to know if an Account is not used will be counting how many blocks since last private key signed this Account as an Active mode as defined on [PIP-0037][2]. 
+
+2. Accounts without coins (amount = 0) can be reused to community usage in a ASK FOR PASA (OP_RECOVER special case) after 4 years if Account has not been used as specified on 1. 
+
+3. Coins stored in Accounts (where amount > 0) can be retrieved to MINER that generates a block as a fee in the OP_RECOVER operation after 10 years if Account has not been used as specified on 1. 
+
+4. ASK FOR PASA will be an OP_RECOVER special case operation signed by an Authority Account, Authority Account will be the Account stored in the type value of Account number 1 ( Account(1).type == Authority Account ). 
+
+5. Accounts 0 to 9 (inclusive) are exempt for OP_RECOVER operation. 
+
+
+## Specification
+
+The following changes are required to implement this in PascalCoin.
+
+### New OP_RECOVER fields
+
+A new field `sign` will be added to OP_RECOVER that will be used in Proposal number 2. Value MUST be empty in other cases. 
+
+```
+  TOpRecoverFoundsData = Record
+    account: Cardinal;
+    n_operation : Cardinal;
+    fee: UInt64;
+    new_publicKey: TAccountKey;
+	// New field for PIP-0042
+    sign: TECDSA_SIG;
+  End;
+```
+
+### Update OP_RECOVER code
+
+#### Changes on check
+
+Check proposals 2 to 5: 
+
+```
+  let A = target PASA 
+  let L4Years = 420480  ((24 hours * 60 minutes) DIV 5 minutes) * 365 days * 4 years)  
+  let L10Years = 1051200  ((24 hours * 60 minutes) DIV 5 minutes) * 365 days * 10 years)  
+  let LCurrentBlock = Current Blockchain new block number
+  
+  // Proposal 5 protection
+  if (A.account<=9) then
+     Error 'Accounts 0..9 are protected';
+  
+  // Proposal 2 protection
+  if (A.updated_on_block_active_mode + L4Years >= LCurrentBlock) then
+     Error 'Account is still active (less than 4 years without private key usage)';  
+  
+  // Proposal 3 protection
+  if (A.updated_on_block_active_mode + L10Years >= LCurrentBlock) AND (A.Balance > 0) then
+     Error 'Account has balance>0 and still active (less than 10 years without private key usage)';
+	 
+  let B = Account(1)
+  let C = Account( B.type ) // Authority account
+  let DATA = OP_RECOVER fields
+
+  // Proposal 4 ASK FOR PASA signed by Authority account
+  if ((DATA.new_publicKey) not null) AND (NOT IsValidSignature(DATA.sign, C.accountInfo.publicKey)) then
+     Error 'Ask for Pasa feature must be signed by Authority account';
+  
+```
+
+#### Changes on Execute
+
+Execution is done only **after checks are passed** 
+
+```
+  // Assume same fields than check code
+   
+  // Ask for Pasa
+  if ((DATA.new_publicKey) not null) then 
+    set A.accountInfo.publicKey = DATA.new_publicKey
+	
+  set FEE = A.balance
+  set A.balance = 0; // Sets Account balance to 0, balance will be a fee for the miner
+  
+  SaveAccount( A );
+  
+  // Only the miner will obtain coins as a Fee of the block, none other can retrieve coins
+  IncrementNewBlockFee( FEE );
+
+```
+
+### Conclusion
+
+Only miner can retrieve coins, this will help and add a miners and pools race 
+
+Current holders will have a reasonable time period (10 years) to hold coins
+
+Ask for Pasa feature will be available since activation thanks to 4 years rule
+
+## Affected PIP's
+
+This PIP deactivates PIP-0012 and PIP-0019 
+
+## Backwards Compatibility
+
+This change is not backwards compatible and requires a hard-fork activation. 
+
+## Links
+
+1. [Original PascalCoin WhitePaper published on July 2016. Accessed 2021-09.][1]
+2. [PIP-0037][2]
+
+[1]: https://github.com/PascalCoin/PascalCoin/blob/c22184dd7a407c6646ab651494822071726ed36e/PascalCoin%20White%20Paper%20-%20EN.pdf
+[2]: https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0037.md

+ 1 - 0
PIP/README.md

@@ -50,4 +50,5 @@ If they wish to continue, copy [this template](PIP-template.md) and ensure your
 | [39](PIP-0039.md)     | Temporary Voting Procedure | Gynther and the Interrim Dao-Team | Process | Cancelled |
 | [40](PIP-0040.md)     | Pascal Governance | Gynther and the Interrim Dao-Team | Process | Cancelled |
 | [41](PIP-0041.md) | Pay To Key: in-protocol PASA distribution | Herman Schoenfeld | Protocol | Draft |
+| [42](PIP-0042.md)     | Update OP_RECOVER to initial sense described on original WhitePaper and allow ASK FOR PASA feature | Albert Molina | Protocol | Proposed |
 

+ 26 - 0
src/core/UAccounts.pas

@@ -118,12 +118,15 @@ Type
     Class procedure SaveTOperationBlockToStream(const stream : TStream; const operationBlock:TOperationBlock);
     Class Function LoadTOperationBlockFromStream(const stream : TStream; var operationBlock:TOperationBlock) : Boolean;
     Class Function AccountToTxt(const Account : TAccount) : String;
+    Class Function AccountCanRecover(const Account: TAccount; currentBlockCount: Cardinal) : Boolean;
   End;
 
   TPCSafeBox = Class;
 
   TAccountKeyArray = array of TAccountKey;
 
+  TAccountList = TList<TAccount>;
+
   // This is a class to quickly find accountkeys and their respective account number/s
 
   { TOrderedAccountKeysList }
@@ -1724,6 +1727,29 @@ begin
       Account.account_data.ToHexaString,Account.account_seal.ToHexaString ]);
 end;
 
+class function TAccountComp.AccountCanRecover(const Account: TAccount; currentBlockCount: Cardinal): Boolean;
+begin
+  Result := True;
+  if TAccountComp.IsAccountBlockedByProtocol(Account.account, currentBlockCount) then begin
+    Result := False; // 'account is blocked for protocol';
+     Exit;
+  end;
+  if TAccountComp.IsAccountLocked(Account.accountInfo,currentBlockCount) then begin
+    Result := False; // 'account is locked';
+    Exit;
+  end;
+  // check boundary 1 gotten from TOpRecoverFounds.DoOperation
+  if( Account.updated_on_block_active_mode + CT_RecoverFoundsWaitInactiveCount >= currentBlockCount ) then begin
+    Result := False; // 'account is active';
+    Exit;
+  end;
+  // check boundary 2 gotten from TOpRecoverFounds.DoOperation
+  if( TAccountComp.AccountBlock(Account.account) + CT_RecoverFoundsWaitInactiveCount >= currentBlockCount ) then begin
+    Result := False; // 'account block is active';
+    Exit;
+  end;
+end;
+
 class function TAccountComp.IsValidAccountInfo(const AAccountInfo: TAccountInfo; ACurrentProtocol : Word; var errors: String): Boolean;
 Var s : String;
 begin

+ 41 - 0
src/core/UBlockChain.pas

@@ -432,6 +432,7 @@ Type
     function LoadBlockFromStream(Stream: TStream; var errors: String): Boolean;
     //
     Function GetMinerRewardPseudoOperation : TOperationResume;
+    Function AddMinerRecover(LRecoverAccounts: TAccountList) : Boolean;
     Function ValidateOperationBlock(var errors : String) : Boolean;
     Property IsOnlyOperationBlock : Boolean read FIsOnlyOperationBlock;
     Procedure Lock;
@@ -2116,6 +2117,46 @@ begin
    Result.OperationTxt := 'Miner reward';
 end;
 
+function TPCOperationsComp.AddMinerRecover(LRecoverAccounts: TAccountList): Boolean;
+var
+  LAccount: TAccount;
+  LOpRecoverFounds: TOpRecoverFounds;
+  i: Integer;
+  errors: string;
+begin
+  Self.Lock;
+  errors := '';
+  Result := True;
+  try
+    for i:=0 to LRecoverAccounts.Count-1 do begin
+      LAccount := LRecoverAccounts[i];
+      LOpRecoverFounds := TOpRecoverFounds.Create(
+        Self.OperationBlock.protocol_version,
+        LAccount.account,
+        LAccount.n_operation+1,
+        LAccount.balance,
+        Self.AccountKey
+      );
+      try
+        if not(
+          Self.AddOperation(
+            True,
+            LOpRecoverFounds,
+            errors
+          )
+        ) then begin
+          // if it fails then it number of operations could be maxed out, not a problem
+          Break;
+        end;
+      finally
+        LOpRecoverFounds.Free;
+      end;
+    end;
+  finally
+    Self.Unlock;
+  end;
+end;
+
 function TPCOperationsComp.ValidateOperationBlock(var errors : String): Boolean;
 Var i : Integer;
 begin

+ 44 - 1
src/core/UPoolMining.pas

@@ -31,7 +31,8 @@ Uses
   {LCLIntf, LCLType, LMessages,}
 {$ENDIF}
   UTCPIP, SysUtils, UThread, SyncObjs, Classes, UJSONFunctions, UPCEncryption, UNode,
-  UCrypto, UAccounts, UConst, UBlockChain, UBaseTypes, UPCDataTypes,
+  UCrypto, UAccounts, UConst, UBlockChain, UBaseTypes, UPCDataTypes, UOpTransaction,
+  UPCAccountsOrdenations,
   {$IFNDEF FPC}System.Generics.Collections{$ELSE}Generics.Collections{$ENDIF};
 
 Const
@@ -140,6 +141,8 @@ Type
   End;
 
 
+  { TPoolMiningServer }
+
   TPoolMiningServer = Class(TNetTcpIpServer)
   private
     FIncomingsCounter : Integer;
@@ -154,6 +157,7 @@ Type
     FMinerOperations : TPCOperationsComp;
     FMaxOperationsPerBlock: Integer;
     FMax0FeeOperationsPerBlock: Integer;
+    Procedure CheckMinerRecover(nbOperations: TPCOperationsComp);
     Procedure DoProcessJSON(json : TPCJSONObject; ResponseMethod : String; Client : TJSONRPCTcpIpClient);
     Procedure OnNodeNewBlock(Sender : TObject);
     Procedure OnNodeOperationsChanged(Sender : TObject);
@@ -801,6 +805,7 @@ begin
       try
         if (Not (TPCOperationsComp.EqualsOperationBlock(FMinerOperations.OperationBlock,LLockedMempool.OperationBlock))) then begin
           FMinerOperations.Clear(true);
+          CheckMinerRecover(LLockedMempool);
           if LLockedMempool.Count>0 then begin
             // First round: Select with fee > 0
             i := 0;
@@ -942,6 +947,44 @@ begin
   End;
 end;
 
+// Looks for accounts to recover, adds up to 100 recoverFounds Operations to nbOperations
+procedure TPoolMiningServer.CheckMinerRecover(nbOperations: TPCOperationsComp);
+var
+  LAccOrd: TAccountsOrderedByUpdatedBlock;
+  LAccount: TAccount;
+  LRecoverAccounts: TList<TAccount>;
+  LIndexKey, LRecIndex, LRecoverAccountsCount: Integer;
+begin
+  LIndexKey := 0;
+  LRecoverAccountsCount := 0;
+  LRecoverAccounts := TList<TAccount>.Create(); // make a list of RecoverAccounts
+  nbOperations.Lock;
+  try
+    LAccOrd := nbOperations.bank.SafeBox.AccountsOrderedByUpdatedBlock; // Walk AccountsOrderedByUpdatedBlock, this keeps a list of the oldest accounts
+    if Assigned(LAccOrd) then begin
+      LAccount := CT_Account_NUL;
+      if LAccOrd.First(LIndexKey) then begin
+        LRecIndex := 0;
+        LRecoverAccountsCount := LAccOrd.Count;
+        while ((LRecIndex < LRecoverAccountsCount) and (LRecIndex < CT_MAX_0_fee_operations_per_block_by_miner)) do begin
+          LAccount := FNodeNotifyEvents.Node.GetMempoolAccount(LIndexKey);
+          if(TAccountComp.AccountCanRecover(LAccount, nbOperations.OperationBlock.block)) then begin // does the AccountCanRecover check, !locked, old enough, etc
+            LRecoverAccounts.Add(LAccount);
+          end else begin
+            Break; // we could not recover this account, then we can never recover move recent accounts
+          end;
+          if Not LAccOrd.Next(LIndexKey) then Break;
+          Inc(LRecIndex);
+        end;
+        nbOperations.AddMinerRecover(LRecoverAccounts);
+      end;
+    end;
+  finally
+    nbOperations.Unlock;
+    LRecoverAccounts.Free; // destroy the list, operations have been added
+  end;
+end;
+
 procedure TPoolMiningServer.OnNewIncommingConnection(Sender: TObject; Client: TNetTcpIpClient);
 var bClient : TJSONRPCTcpIpClient;
   jsonobj : TPCJSONObject;

+ 10 - 6
src/pascalcoin_wallet_classic.lpi

@@ -42,7 +42,7 @@
         <PackageName Value="LCL"/>
       </Item1>
     </RequiredPackages>
-    <Units Count="37">
+    <Units Count="39">
       <Unit0>
         <Filename Value="pascalcoin_wallet_classic.dpr"/>
         <IsPartOfProject Value="True"/>
@@ -222,6 +222,15 @@
         <HasResources Value="True"/>
         <ResourceBaseClass Value="Form"/>
       </Unit36>
+      <Unit37>
+        <Filename Value="gui-classic\UFRMAskForAccount.pas"/>
+        <IsPartOfProject Value="True"/>
+        <HasResources Value="True"/>
+      </Unit37>
+      <Unit38>
+        <Filename Value="core\UPCTNetDataExtraMessages.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit38>
     </Units>
   </ProjectOptions>
   <CompilerOptions>
@@ -240,11 +249,6 @@
         <SyntaxMode Value="Delphi"/>
       </SyntaxOptions>
     </Parsing>
-    <CodeGeneration>
-      <Optimizations>
-        <OptimizationLevel Value="2"/>
-      </Optimizations>
-    </CodeGeneration>
     <Linking>
       <Debugging>
         <GenerateDebugInfo Value="False"/>