Skip to content

Commit

Permalink
Merge pull request #71 from PascalCoinDev/master
Browse files Browse the repository at this point in the history
PIP-0043
  • Loading branch information
PascalCoinDev committed Mar 14, 2023
2 parents 02e64ce + a58f925 commit 8f53f3e
Show file tree
Hide file tree
Showing 10 changed files with 546 additions and 66 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog

## Build 6 (Pending)
- MANDATORY UPGRADE - HARD FORK ACTIVATION WILL OCCUR ON BLOCK **(pending)**
- Upgrade to Protocol 6 (Hard fork)
- Implementation of PIP-0043 (Update OP_RECOVER to recover only non used, not named PASA's) -> https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0043.md
- Improvements on downloading Safebox (fresh installation)


## Build 5.7 - 2021-12-23
- This version will not propagate 0-Fee operations, but will allow 0-Fee operations to the blockchain (CT_AllowPropagate0feeOperations=False)
- A wallet that wants to execute 0-Fee operations will need to connect to a miner/pool/node running a 5.6 version or solomine
Expand Down
73 changes: 73 additions & 0 deletions PIP/PIP-0043.md
@@ -0,0 +1,73 @@
<pre>
PIP: PIP-0043
Title: Update OP_RECOVER to recover only non used, not named PASA's
Type: Protocol
Impact: Hard-Fork
Author: Albert Molina <bpascalblockchain@gmail.com>
Copyright: Albert Molina, 2023 (All Rights Reserved)
Comments-URI: https://discord.gg/Scr8mcwnrC (Discord channel #pip-43)
Status: Proposed
Created: 2023-03-10
</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 and also a community poll made on discord channel

## 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 usage of 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 was mixing coins (**PASC**) and accounts (**PASA**), because what is necessary in PascalCoin is an Account (aka PASA), so we can focus on recover PASA instead of recover coins inside PASA

## Proposal

This PIP specifies a more accurated OP_RECOVER that was discussed on Discord Channel

See poll results: https://discordapp.com/channels/383064643482025984/391780165669093377/719437469329915945
```
Poll on Discord
https://discordapp.com/channels/383064643482025984/391780165669093377/719437469329915945
RESULTS ON 2020-07-21
1 (22 votes) - Remove PASC/PASA Recovery rule
2 (27 votes) - Recover only EMPTY non used, not named PASA's
3 (3 votes) - Change Recovery to 10 year rule
4 (2 votes) - Leave As Is.
Winner option 2: Will apply on next Hard Fork (Protocol 6)
```


## Implementation

https://github.com/PascalCoin/PascalCoin/commit/290ba9c288202250f891945f629a3d2aff907e08

## Affected PIP's

This PIP deactivates PIP-0012 and PIP-0042

## 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]

[1]: https://github.com/PascalCoin/PascalCoin/blob/c22184dd7a407c6646ab651494822071726ed36e/PascalCoin%20White%20Paper%20-%20EN.pdf
1 change: 1 addition & 0 deletions PIP/README.md
Expand Up @@ -51,4 +51,5 @@ If they wish to continue, copy [this template](PIP-template.md) and ensure your
| [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 |
| [43](PIP-0043.md) | Update OP_RECOVER to recover only non used, not named PASA's | Albert Molina | Protocol | Proposed |

20 changes: 18 additions & 2 deletions src/core/UAccounts.pas
Expand Up @@ -281,7 +281,8 @@ TProgressNotifyManyHelper = record helper for TProgressNotifyMany
Function LoadSafeBoxChunkFromStream(Stream : TStream; checkAll : Boolean; checkSafeboxHash : TRawBytes; progressNotify : TProgressNotify; previousCheckedSafebox : TPCSafebox; var ALastReadBlock : TBlockAccount; var errors : String) : Boolean;
Function LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; var LastReadBlock : TBlockAccount; var errors : String) : Boolean; overload;
Function LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; checkSafeboxHash : TRawBytes; progressNotify : TProgressNotify; previousCheckedSafebox : TPCSafebox; var ALastReadBlock : TBlockAccount; var errors : String) : Boolean; overload;
Class Function LoadSafeBoxStreamHeader(Stream : TStream; var sbHeader : TPCSafeBoxHeader) : Boolean;
Class Function LoadSafeBoxStreamHeader(Stream : TStream; var sbHeader : TPCSafeBoxHeader; out AStreamFinalPos : Int64) : Boolean; overload;
Class Function LoadSafeBoxStreamHeader(Stream : TStream; var sbHeader : TPCSafeBoxHeader) : Boolean; overload;
Class Function SaveSafeBoxStreamHeader(Stream : TStream; protocol : Word; OffsetStartBlock, OffsetEndBlock, CurrentSafeBoxBlocksCount : Cardinal) : Boolean;
Class Function MustSafeBoxBeSaved(BlocksCount : Cardinal) : Boolean;
Class Function InitialSafeboxHash : TRawBytes;
Expand Down Expand Up @@ -3837,8 +3838,16 @@ function TPCSafeBox.LoadSafeBoxChunkFromStream(Stream : TStream; checkAll : Bool


function TPCSafeBox.LoadSafeBoxFromStream(Stream : TStream; checkAll : Boolean; checkSafeboxHash : TRawBytes; progressNotify : TProgressNotify; previousCheckedSafebox : TPCSafebox; var ALastReadBlock : TBlockAccount; var errors : String) : Boolean;
var Ltc : TTickCount;
begin
Ltc := TPlatform.GetTickCount;
Result := LoadSafeBoxChunkFromStream(Stream,checkAll,checkSafeboxHash,progressNotify,previousCheckedSafebox,ALastReadBlock,errors);
if Result then begin
while LoadSafeBoxChunkFromStream(Stream,checkAll,checkSafeboxHash,progressNotify,previousCheckedSafebox,ALastReadBlock,errors) do begin
TLog.NewLog(ltdebug,ClassName,Format('Loading safebox from stream... %.2f secs',[TPlatform.GetElapsedMilliseconds(Ltc)/1000]));
end;
end;
TLog.NewLog(ltdebug,ClassName,Format('Finalized Loading safebox from stream in %.2f secs',[TPlatform.GetElapsedMilliseconds(Ltc)/1000]));
end;

function TPCSafeBox.LoadSafeBoxFromStream(Stream: TStream; checkAll: Boolean; var LastReadBlock: TBlockAccount; var errors: String): Boolean;
Expand All @@ -3848,7 +3857,13 @@ function TPCSafeBox.LoadSafeBoxFromStream(Stream: TStream; checkAll: Boolean; va
Result := LoadSafeBoxFromStream(Stream,checkAll,Nil,pn,Nil,LastReadBlock,errors);
end;

class function TPCSafeBox.LoadSafeBoxStreamHeader(Stream: TStream; var sbHeader : TPCSafeBoxHeader) : Boolean;
class function TPCSafeBox.LoadSafeBoxStreamHeader(Stream: TStream; var sbHeader: TPCSafeBoxHeader): Boolean;
var LPos : Int64;
begin
Result := LoadSafeBoxStreamHeader(Stream,sbHeader,LPos);
end;

class function TPCSafeBox.LoadSafeBoxStreamHeader(Stream: TStream; var sbHeader : TPCSafeBoxHeader; out AStreamFinalPos : Int64) : Boolean;
// This function reads SafeBox stream info and sets position at offset start zone if valid, otherwise sets position to actual position
Var w : Word;
raw : TRawBytes;
Expand Down Expand Up @@ -3881,6 +3896,7 @@ class function TPCSafeBox.LoadSafeBoxStreamHeader(Stream: TStream; var sbHeader
If (Stream.Size<offsetPos + (endBlocks)) then exit;
Stream.Position:=offsetPos + endBlocks;
If TStreamOp.ReadAnsiString(Stream,sbHeader.safeBoxHash)<0 then exit;
AStreamFinalPos := Stream.position;
// Back
Stream.Position:=offsetPos;
Result := True;
Expand Down
3 changes: 2 additions & 1 deletion src/core/UBaseTypes.pas
Expand Up @@ -218,7 +218,8 @@ function TRawBytesHelper.FromSerialized(const ASerialized: TBytes; ACheckLength
Move(ASerialized[0],Lsize,2);
if (2 + Lsize > Length(ASerialized)) then Exit(False);
SetLength(Self,Lsize);
Move(ASerialized[2],Self[0],Lsize);
if Lsize>0 then
Move(ASerialized[2],Self[0],Lsize);
Result := True;
end;

Expand Down
9 changes: 1 addition & 8 deletions src/core/UBlockChain.pas
Expand Up @@ -1311,18 +1311,11 @@ function TPCBank.IsReady(var CurrentProcess: String): Boolean;

function TPCBank.LoadBankFileInfo(const AFilename: String;
var ASafeBoxHeader: TPCSafeBoxHeader): Boolean;
var fs: TFileStream;
begin
Result := false;
ASafeBoxHeader := CT_PCSafeBoxHeader_NUL;
If Not FileExists(AFilename) then exit;
fs := TFileStream.Create(AFilename,fmOpenRead);
try
fs.Position:=0;
Result := SafeBox.LoadSafeBoxStreamHeader(fs,ASafeBoxHeader);
finally
fs.Free;
end;
Result := TPCSafeboxChunks.GetSafeboxHeaderFromFile(AFilename,ASafeBoxHeader);
end;

function TPCBank.LoadBankFromChunks(AChunks : TPCSafeboxChunks;
Expand Down
147 changes: 122 additions & 25 deletions src/core/UChunk.pas
Expand Up @@ -36,7 +36,7 @@ interface
{$ELSE}
zlib,
{$ENDIF}
UAccounts, ULog, UConst, UCrypto, UBaseTypes, UPCDataTypes;
UBaseTypes, UPCDataTypes;

type

Expand All @@ -55,26 +55,40 @@ interface

TPCSafeboxChunks = Class
private
FChunks : Array of TStream;
Type TChunkStreamInfo = Record
stream : TStream;
streamInitialPosition : Int64;
streamFinalPosition : Int64;
freeStreamOnClear : Boolean;
End;
private
FChunks : Array of TChunkStreamInfo;
FIsMultiChunkStream : Boolean;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function Count : Integer;
procedure AddChunk(ASafeboxStreamChunk : TStream);
function AddChunk(ASafeboxStreamChunk : TStream; AFreeStreamOnClear : Boolean; ARaiseOnError : Boolean = false) : Boolean;
function GetSafeboxChunk(index : Integer) : TStream;
function GetSafeboxChunkHeader(index : Integer) : TPCSafeBoxHeader;
function IsComplete : Boolean;
function GetSafeboxHeader : TPCSafeBoxHeader;
function SaveSafeboxfile(AFileName : String) : Boolean;
function SaveSafeboxStream(AStream : TStream) : Boolean;
class function GetSafeboxHeaderFromStream(AStream : TStream; var APCSafeBoxHeader : TPCSafeBoxHeader) : Boolean;
class function GetSafeboxHeaderFromFile(AFilename : String; var APCSafeBoxHeader : TPCSafeBoxHeader) : Boolean;
end;

implementation

uses UAccounts, ULog, UConst;
{ TPCSafeboxChunks }

constructor TPCSafeboxChunks.Create;
begin
SetLength(FChunks,0);
FIsMultiChunkStream := False;
end;

destructor TPCSafeboxChunks.Destroy;
Expand All @@ -87,46 +101,72 @@ procedure TPCSafeboxChunks.Clear;
var i : Integer;
begin
For i:=0 to Count-1 do begin
FChunks[i].Free;
if (FChunks[i].freeStreamOnClear) then FChunks[i].stream.Free;
if FIsMultiChunkStream then break; // When MultiChunk first stream is the same for all
end;
SetLength(FChunks,0);
FIsMultiChunkStream := False;
end;

function TPCSafeboxChunks.Count: Integer;
begin
Result := Length(FChunks);
end;

procedure TPCSafeboxChunks.AddChunk(ASafeboxStreamChunk: TStream);
function TPCSafeboxChunks.AddChunk(ASafeboxStreamChunk: TStream; AFreeStreamOnClear : Boolean; ARaiseOnError : Boolean) : Boolean;
var LLastHeader, LsbHeader : TPCSafeBoxHeader;
LChunk : TChunkStreamInfo;
LCount : Integer;
begin
If Not TPCSafeBox.LoadSafeBoxStreamHeader(ASafeboxStreamChunk,LsbHeader) then begin
Raise EPCChunk.Create('SafeBoxStream is not a valid SafeBox to add!');
if FIsMultiChunkStream then begin
if ARaiseOnError then raise EPCChunk.Create('Cannot add to a MultiChunk Stream')
else Exit(False);
end;
if (Count>0) then begin
LLastHeader := GetSafeboxChunkHeader(Count-1);
if (LsbHeader.ContainsFirstBlock)
or (LsbHeader.startBlock<>LLastHeader.endBlock+1)
or (LLastHeader.ContainsLastBlock)
or (LsbHeader.protocol<>LLastHeader.protocol)
or (LsbHeader.blocksCount<>LLastHeader.blocksCount)
or (Not LsbHeader.safeBoxHash.IsEqualTo( LLastHeader.safeBoxHash ))
then begin
raise EPCChunk.Create(Format('Cannot add %s at (%d) %s',[LsbHeader.ToString,Length(FChunks),LLastHeader.ToString]));
LCount := 0;
repeat
LChunk.streamInitialPosition := ASafeboxStreamChunk.position;
LChunk.stream := ASafeboxStreamChunk;
LChunk.freeStreamOnClear := AFreeStreamOnClear;
If Not TPCSafeBox.LoadSafeBoxStreamHeader(ASafeboxStreamChunk,LsbHeader,LChunk.streamFinalPosition) then begin
if (ARaiseOnError) and (LCount=0) then Raise EPCChunk.Create('SafeBoxStream is not a valid SafeBox to add!')
else Exit(LCount>0);
end else if LCount>0 then FIsMultiChunkStream := True;

if (Count>0) then begin
LLastHeader := GetSafeboxChunkHeader(Count-1);
if (LsbHeader.ContainsFirstBlock)
or (LsbHeader.startBlock<>LLastHeader.endBlock+1)
or (LLastHeader.ContainsLastBlock)
or (LsbHeader.protocol<>LLastHeader.protocol)
or (LsbHeader.blocksCount<>LLastHeader.blocksCount)
or (Not LsbHeader.safeBoxHash.IsEqualTo( LLastHeader.safeBoxHash ))
then begin
if ARaiseOnError then raise EPCChunk.Create(Format('Cannot add %s at (%d) %s',[LsbHeader.ToString,Length(FChunks),LLastHeader.ToString]))
else Exit(False);
end;
end else if (Not LsbHeader.ContainsFirstBlock) then begin
if ARaiseOnError then raise EPCChunk.Create(Format('Cannot add %s',[LsbHeader.ToString]))
else Exit(False);
end;
end else if (Not LsbHeader.ContainsFirstBlock) then begin
raise EPCChunk.Create(Format('Cannot add %s',[LsbHeader.ToString]));
end;
//
SetLength(FChunks,Length(FChunks)+1);
FChunks[High(FChunks)] := ASafeboxStreamChunk;
//
ASafeboxStreamChunk.Position := LChunk.streamFinalPosition;
//
SetLength(FChunks,Length(FChunks)+1);
FChunks[High(FChunks)] := LChunk;
inc(LCount);
until false;
Result := True;
end;

function TPCSafeboxChunks.GetSafeboxChunk(index: Integer): TStream;
begin
if (index<0) or (index>=Count) then raise EPCChunk.Create(Format('Invalid index %d of %d',[index,Length(FChunks)]));
Result := FChunks[index];
Result.Position := 0;
if FIsMultiChunkStream then begin
Result := FChunks[0].stream;
end else begin
Result := FChunks[index].stream;
end;
Result.Position := FChunks[index].streamInitialPosition;
end;

function TPCSafeboxChunks.GetSafeboxChunkHeader(index: Integer): TPCSafeBoxHeader;
Expand All @@ -146,13 +186,70 @@ function TPCSafeboxChunks.IsComplete: Boolean;
end;
end;

function TPCSafeboxChunks.SaveSafeboxfile(AFileName: String): Boolean;
var fs : TFileStream;
begin
fs := TFileStream.Create(AFilename,fmCreate);
try
Result := SaveSafeboxStream(fs);
finally
fs.Free;
end;
end;


function TPCSafeboxChunks.SaveSafeboxStream(AStream: TStream): Boolean;
Var
iChunk : Integer;
Lstream : TStream;
begin
Result := false;
for iChunk := 0 to Count-1 do begin
Lstream := GetSafeboxChunk(iChunk);
AStream.CopyFrom(LStream,FChunks[iChunk].streamFinalPosition - FChunks[iChunk].streamInitialPosition);
end;
Result := True;
end;


function TPCSafeboxChunks.GetSafeboxHeader: TPCSafeBoxHeader;
begin
if Not IsComplete then Raise EPCChunk.Create(Format('Chunks are not complete %d',[Length(FChunks)]));
Result := GetSafeboxChunkHeader(Count-1);
Result.startBlock := 0;
end;

class function TPCSafeboxChunks.GetSafeboxHeaderFromFile(AFilename: String;
var APCSafeBoxHeader: TPCSafeBoxHeader): Boolean;
var fs: TFileStream;
begin
APCSafeBoxHeader := CT_PCSafeBoxHeader_NUL;
if (AFileName.trim()='') or (Not FileExists(AFileName)) then Exit(False);
fs := TFileStream.Create(AFilename,fmOpenRead);
try
Result := TPCSafeboxChunks.GetSafeboxHeaderFromStream(fs,APCSafeBoxHeader);
finally
fs.Free;
end;
end;

class function TPCSafeboxChunks.GetSafeboxHeaderFromStream(AStream: TStream;
var APCSafeBoxHeader: TPCSafeBoxHeader): Boolean;
var LChunks : TPCSafeboxChunks;
begin
APCSafeBoxHeader := CT_PCSafeBoxHeader_NUL;
LChunks := TPCSafeboxChunks.Create;
try
if LChunks.AddChunk(AStream,False,False) then begin
if LChunks.IsComplete then APCSafeBoxHeader := LChunks.GetSafeboxHeader
else APCSafeBoxHeader := LChunks.GetSafeboxChunkHeader(0);
Result := True;
end else Result := False;
finally
LChunks.Free;
end;
end;

{ TPCChunk }

class function TPCChunk.SaveSafeBoxChunkFromSafeBox(SafeBoxStream, DestStream : TStream; fromBlock, toBlock: Cardinal; var errors : String) : Boolean;
Expand Down

0 comments on commit 8f53f3e

Please sign in to comment.