diff --git a/lastrelease.txt b/lastrelease.txt index 649f29f..7dfd3d4 100644 --- a/lastrelease.txt +++ b/lastrelease.txt @@ -1 +1 @@ -0.4.2Da1 0.4.2Da1 x {LastOfficial} {LastBeta} {TestNet} \ No newline at end of file +0.4.2Da2 0.4.2Da2 x {LastOfficial} {LastBeta} {TestNet} \ No newline at end of file diff --git a/masterpaskalform.pas b/masterpaskalform.pas index 98265e3..b2993d6 100644 --- a/masterpaskalform.pas +++ b/masterpaskalform.pas @@ -567,7 +567,7 @@ TForm1 = class(TForm) HideCommands : String = 'CLEAR SENDPOOLSOLUTION SENDPOOLSTEPS DELBOTS'; CustomValid : String = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@*+-_:'; - MainnetVersion = '0.4.2'; + MainnetVersion = '0.4.3'; {$IFDEF WINDOWS} RestartFileName = 'launcher.bat'; updateextension = 'zip'; @@ -576,9 +576,9 @@ TForm1 = class(TForm) RestartFileName = 'launcher.sh'; updateextension = 'tgz'; {$ENDIF} - NodeRelease = 'Da2'; - OficialRelease = true; - BetaRelease = false; + NodeRelease = 'Aa1'; + OficialRelease = False; + BetaRelease = True; VersionRequired = '0.4.2'; BuildDate = 'April 2024'; {Developer addresses} @@ -619,7 +619,7 @@ TForm1 = class(TForm) var Form1 : TForm1; - Customizationfee : int64 = InitialReward div ComisionCustom; + //Customizationfee : int64 = InitialReward div ComisionCustom; {Options} FileAdvOptions : textfile; S_AdvOpt : boolean = false; @@ -638,6 +638,7 @@ TForm1 = class(TForm) WO_StopGUI : boolean = false; WO_BlockDB : boolean = false; WO_PRestart : int64 = 0; + WO_skipBlocks : boolean = false; RPCFilter : boolean = true; RPCWhitelist : string = '127.0.0.1,localhost'; RPCBanned : string = ''; @@ -2645,6 +2646,8 @@ procedure TForm1.IdTCPServer1Connect(AContext: TIdContext); ContextData : TServerTipo; ThisSlot : integer; PeerUTC : int64; + BlockZipName: string = ''; + BlockZipsize: int64; Begin GoAhead := true; ContextData := TServerTipo.Create; @@ -2720,6 +2723,23 @@ procedure TForm1.IdTCPServer1Connect(AContext: TIdContext); MemStream.Free; TryCloseServerConnection(AContext); end + else if parameter(LLine,0) = 'NSLBLOCKS' then + begin + MemStream := TMemoryStream.Create; + BlockZipsize := GetBlocksAsStream(MemStream,StrToIntDef(parameter(LLine,1),-1),MyLastBlock); + If BlockZipsize > 0 then + begin + TRY + Acontext.Connection.IOHandler.WriteLn('BLOCKZIP '+inttoStr(BlockZipsize)); + Acontext.connection.IOHandler.Write(MemStream,0,true); + EXCEPT on E:Exception do + begin + end; + END; {TRY} + end; + MemStream.Free; + TryCloseServerConnection(AContext); + end else if parameter(LLine,0) = 'GETZIPSUMARY' then // begin MemStream := TMemoryStream.Create; @@ -2833,7 +2853,7 @@ procedure TForm1.IdTCPServer1Exception(AContext: TIdContext;AException: Exceptio Address := DireccionesPanel.Cells[0,DireccionesPanel.Row]; if not IsValidHashAddress(address) then info('Address already customized') else if AddressAlreadyCustomized(address) then info('Address already customized') - else if GetAddressBalanceIndexed(Address)-GetAddressPendingPays(address)< Customizationfee then info('Insufficient funds') + else if GetAddressBalanceIndexed(Address)-GetAddressPendingPays(address)< GetCustFee(MyLastBlock) then info('Insufficient funds') else begin DireccionesPanel.Enabled:=false; diff --git a/mpblock.pas b/mpblock.pas index 594066f..537c2bf 100644 --- a/mpblock.pas +++ b/mpblock.pas @@ -124,6 +124,7 @@ implementation Begin +if WO_skipBlocks then exit; if GetCFGDataStr(0) = 'STOP' then begin ClearAllPending; diff --git a/mpdisk.pas b/mpdisk.pas index f5914b5..aca39de 100644 --- a/mpdisk.pas +++ b/mpdisk.pas @@ -257,6 +257,8 @@ implementation writeln(FileAdvOptions,'BlocksDB '+BoolToStr(WO_BlockDB,true)); writeln(FileAdvOptions,'//Restart periodically the node'); writeln(FileAdvOptions,'PRestart '+IntToStr(WO_PRestart)); + writeln(FileAdvOptions,'//Skip new blocks creation'); + writeln(FileAdvOptions,'SkipBlocks '+BoolToStr(WO_skipBlocks,true)); writeln(FileAdvOptions,'//Mainform coordinates. Do not manually change this values'); writeln(FileAdvOptions,Format('FormState %d %d %d %d %d',[Form1.Top,form1.Left,form1.Width,form1.Height,form1.WindowState])); @@ -330,6 +332,8 @@ implementation if parameter(linea,0) ='SendReport' then WO_SendReport:=StrToBool(Parameter(linea,1)); if parameter(linea,0) ='BlocksDB' then WO_BlockDB:=StrToBool(Parameter(linea,1)); if parameter(linea,0) ='PRestart' then WO_PRestart:=StrToIntDef(Parameter(linea,1),0); + if parameter(linea,0) ='SkipBlocks' then WO_skipBlocks:=StrToBool(Parameter(linea,1)); + if parameter(linea,0) ='MultiSend' then WO_MultiSend:=StrToBool(Parameter(linea,1)); @@ -683,7 +687,7 @@ function UnZipUpdateFromRepo(Tver,TArch:String):boolean; if ArrayOrders[cont].OrderType='SNDGVT' then begin Inc(GVTsTrfer); - SummaryPay(ArrayOrders[cont].sender,Customizationfee,BlockNumber); + SummaryPay(ArrayOrders[cont].sender,GetCustFee(BlockNumber),BlockNumber); ChangeGVTOwner(StrToIntDef(ArrayOrders[cont].Reference,100),ArrayOrders[cont].sender,ArrayOrders[cont].Receiver); end; if ArrayOrders[cont].OrderType='TRFR' then diff --git a/mpparser.pas b/mpparser.pas index 23d28bb..f49e3ca 100644 --- a/mpparser.pas +++ b/mpparser.pas @@ -63,6 +63,7 @@ function ShowPrivKey(linea:String;ToConsole:boolean = false):String; Procedure NewAddressFromKeys(inputline:string); Procedure TestHashGeneration(inputline:string); Procedure CompareHashes(inputline:string); +Procedure CreateMultiAddress(Inputline:String); // CONSULTING Procedure ListGVTs(); @@ -272,6 +273,7 @@ function GetOpData(textLine:string):String; else if UpperCase(Command) = 'SENDREPORT' then SEndFileViaTCP(ResumeLogFilename,'REPORT','debuglogs.nosocoin.com:18081',18081) else if UpperCase(Command) = 'GETDBLB' then ToLog('console',GetDBLastBlock.ToString) else if UpperCase(Command) = 'ORDINFO' then OrdInfo(LineText) +else if UpperCase(Command) = 'GETMULTI' then CreateMultiAddress(LineText) // New system @@ -647,7 +649,7 @@ function GetWalletBalance(): Int64; ToLog('console','Alias can not be a valid address'); //'Alias can not be a valid address' procesar := false; end; -if GetWallArrIndex(WallAddIndex(address)).Balance < Customizationfee then +if GetWallArrIndex(WallAddIndex(address)).Balance < GetCustFee(MyLastBlock) then begin ToLog('console','Insufficient balance'); //'Insufficient balance' procesar := false; @@ -687,7 +689,7 @@ function GetWalletBalance(): Int64; GetWallArrIndex(WallAddIndex(address)).PublicKey+' '+ // sender GetWallArrIndex(WallAddIndex(address)).Hash+' '+ // address AddAlias+' '+ // receiver - IntToStr(Customizationfee)+' '+ // Amountfee + IntToStr(GetCustFee(MyLastBlock))+' '+ // Amountfee '0'+' '+ // amount trfr '[[RESULT]] '+ TrfrHash); // trfrhash @@ -852,7 +854,7 @@ function SendFunds(LineText:string;showOutput:boolean=true):string; if showOutput then ToLog('console','You do not own that GVT'); exit; end; -if GetAddressAvailable(GVTOwner)getmulti 2,3 Nxxx,Nxxxx,Nxxxx +Procedure CreateMultiAddress(Inputline:String); +var + source : string = ''; + FullSource : string = ''; + AddType : string; + NewAdd : String; + AddsNeeded : integer; + AddsTotal : integer; + ErrorMsg : string = ''; + NewAddress : WalletData; +Begin + AddType := parameter(Inputline,1); + AddType := StringReplace(AddType,',',' ',[rfReplaceAll, rfIgnoreCase]); + AddsNeeded := StrToIntDef(Parameter(AddType,0),-1); + AddsTotal := StrToIntDef(Parameter(AddType,1),-1); + if Addtype = '' then ErrorMsg := 'getmulti needed,total list,of,addresses'; + if ( (AddsTotal<2) or (AddsTotal>7) ) then ErrorMsg := 'Wrong number of total addresses'; + if ( (AddsNeeded <1) or (AddsNeeded>=AddsTotal) ) then ErrorMsg := 'Wrong number of needed addresses'; + if ErrorMsg <> '' then + begin + ToLog('Console',ErrorMsg); + Exit; + end; + source := parameter(Inputline,2); + if not GetMultiSource(Source,AddsTotal,FullSource) then + begin + ToLog('Console','Error: '+FullSource); + Exit; + end; + AddType := StringReplace(AddType,' ',',',[rfReplaceAll, rfIgnoreCase]); + NewAdd := GetAddressFromPublicKey(AddType+':'+FullSource,AddTypeMulti); + if IsValidHashAddress(NewAdd) then + begin + ToLog('Console','New multiAddress: '+NewAdd); + NewAddress := Default(WalletData); + NewAddress.Hash:= NewAdd; + NewAddress.PublicKey:=AddType+':'+FullSource; + InsertToWallArr(NewAddress); + S_Wallet := true; + U_DirPanel := true; + end + else ToLog('Console','Something went wrong...'); +End; + // PSOs testing functions Procedure TestNewPSO(Dataline:String); diff --git a/mpprotocol.pas b/mpprotocol.pas index 3a8119e..9bcb115 100644 --- a/mpprotocol.pas +++ b/mpprotocol.pas @@ -681,7 +681,7 @@ function CreateZipBlockfile(firstblock:integer):string; Address := GetAddressFromPublicKey(OrderInfo.sender); if address <> OrderInfo.Address then ErrorCode := 1; // La direccion no dispone de fondos -if GetAddressBalanceIndexed(Address)-GetAddressPendingPays(Address) < Customizationfee then ErrorCode:=2; +if GetAddressBalanceIndexed(Address)-GetAddressPendingPays(Address) < GetCustFee(MyLastBlock) then ErrorCode:=2; if TranxAlreadyPending(OrderInfo.TrfrID ) then ErrorCode:=3; if OrderInfo.TimeStamp < LastBlockData.TimeStart then ErrorCode:=4; if TrxExistsInLastBlock(OrderInfo.TrfrID) then ErrorCode:=5; @@ -892,7 +892,7 @@ function ValidateTrfr(order:Torderdata;Origen:String):integer; Address := GetAddressFromPublicKey(OrderInfo.sender); if address <> OrderInfo.Address then ErrorCode := 1; // La direccion no dispone de fondos -if GetAddressBalanceIndexed(Address)-GetAddressPendingPays(Address) < Customizationfee then ErrorCode:=2; +if GetAddressBalanceIndexed(Address)-GetAddressPendingPays(Address) < GetCustFee(MyLastBlock) then ErrorCode:=2; if TranxAlreadyPending(OrderInfo.TrfrID ) then ErrorCode:=3; if OrderInfo.TimeStamp < LastBlockData.TimeStart then ErrorCode:=4; if TrxExistsInLastBlock(OrderInfo.TrfrID) then ErrorCode:=5; diff --git a/nosoblock.pas b/nosoblock.pas index 678084a..536364a 100644 --- a/nosoblock.pas +++ b/nosoblock.pas @@ -11,7 +11,8 @@ INTERFACE uses - Classes, SysUtils, FileUtil, NosoDebug, NosoUnit, Nosocrypto,nosogeneral; + Classes, SysUtils, FileUtil, Zipper, + NosoDebug, NosoUnit, Nosocrypto,nosogeneral; Type TDBRecord = record @@ -57,6 +58,7 @@ function GetBlockTrxs(BlockNumber:integer):TBlockOrdersArray; function LoadBlockDataHeader(BlockNumber:integer):BlockHeaderData; Function SaveStreamAsZipBlocks(Const LStream:TMemoryStream):boolean; +function GetBlocksAsStream(out LMs:TMemoryStream;firstblock, CurrentLastblock:integer):Int64; var BlockDirectory : string = 'NOSODATA'+DirectorySeparator+'BLOCKS'+DirectorySeparator; @@ -421,6 +423,49 @@ function LoadBlockDataHeader(BlockNumber:integer):BlockHeaderData; END{Try}; End; +// Creates the zip block file +function GetBlocksAsStream(out LMs:TMemoryStream;firstblock, CurrentLastblock:integer):Int64; +var + MyZipFile: TZipper; + ZipFileName:String; + LastBlock : integer; + contador : integer; + filename, archivename: String; +Begin + result := 0; + LastBlock := FirstBlock + 100; if LastBlock>CurrentLastblock then LastBlock := CurrentLastblock; + MyZipFile := TZipper.Create; + ZipFileName := BlockDirectory+'Blocks_'+IntToStr(FirstBlock)+'_'+IntToStr(LastBlock)+'.zip'; + MyZipFile.FileName := ZipFileName; + TRY + for contador := FirstBlock to LastBlock do + begin + filename := BlockDirectory+IntToStr(contador)+'.blk'; + {$IFDEF WINDOWS} + archivename:= StringReplace(filename,'\','/',[rfReplaceAll]); + {$ENDIF} + {$IFDEF UNIX} + archivename:= filename; + {$ENDIF} + MyZipFile.Entries.AddFileEntry(filename, archivename); + end; + MyZipFile.ZipAllFiles; + //result := ZipFileName; + EXCEPT ON E:Exception do + begin + ToLog('exceps',FormatDateTime('dd mm YYYY HH:MM:SS.zzz', Now)+' -> '+'Error zipping block files: '+E.Message); + end; + END; + MyZipFile.Free; + TRY + LMs.LoadFromFile(ZipFileName); + result:= LMs.Size; + LMs.Position:=0; + EXCEPT ON E:Exception do + END{Try}; + Trydeletefile(ZipFileName); +End; + {$ENDREGION Blocks Files management} INITIALIZATION diff --git a/nosocrypto.pas b/nosocrypto.pas index 59284b7..ecbc39f 100644 --- a/nosocrypto.pas +++ b/nosocrypto.pas @@ -15,7 +15,7 @@ Classes, SysUtils, strutils, HlpHashFactory, md5, ClpConverters,ClpBigInteger,SbpBase58, - mpsignerutils, base64, NosoDebug; + mpsignerutils, base64, NosoDebug, nosogeneral; Type @@ -34,7 +34,7 @@ function HashMD160String(StringToHash:string):String; Function IsValid58(base58text:string):boolean; Function GetStringSigned(StringtoSign, PrivateKey:String):String; Function VerifySignedString(StringToVerify,B64String,PublicKey:String):boolean; -function GetAddressFromPublicKey(PubKey:String):String; +function GetAddressFromPublicKey(PubKey:String;AddType : integer = 0):String; function NewGetAddressFromPublicKey(PubKey:String):String; function FutureGetAddressFromPublicKey(const PubKey: String): String; Function GenerateNewAddress(out pubkey:String;out privkey:String):String; @@ -45,6 +45,7 @@ function GetOrderHash(TextLine:string):String; Function GetCertificate(Pubkey,privkey,currtime:string):string; Function CheckCertificate(certificate:string;out TimeStamp:String):string; Function CheckHashDiff(Target,ThisHash:String):string; +Function GetMultiSource(Source: String;AddsTotal:integer;Out OrderedSource:String) : boolean; {New base conversion functions} function B10ToB16(const sVal: String): String; @@ -79,6 +80,8 @@ function BMDecToHex(numero:string):string; HexAlphabet : string = '0123456789ABCDEF'; B36Alphabet : string = '0123456789abcdefghijklmnopqrstuvwxyz'; B58Alphabet : string = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; + AddtypeReg = 0; + AddTypeMulti = 1; IMPLEMENTATION @@ -239,7 +242,7 @@ function IsValid58(base58text:string):boolean; End; // Generates the public hash from the public key -function GetAddressFromPublicKey(PubKey:String):String; +function GetAddressFromPublicKey(PubKey:String;AddType : integer = 0):String; var PubSHAHashed,Hash1,Hash2,clave:String; sumatoria : string; @@ -250,7 +253,8 @@ function GetAddressFromPublicKey(PubKey:String):String; sumatoria := BMB58resumen(Hash1); clave := BMDecTo58(sumatoria); hash2 := hash1+clave; -Result := 'N'+hash2; +if AddType = 0 then Result := 'N'+hash2 +else if Addtype = 1 then Result := 'M'+Hash2; End; function NewGetAddressFromPublicKey(PubKey:String):String; @@ -322,14 +326,17 @@ function FutureGetAddressFromPublicKey(const PubKey: String): String; {Checks if a string is a valid address hash} Function IsValidHashAddress(Address:String):boolean; var - OrigHash : String; + OrigHash : String; + FirstChar : string; Begin result := false; - if ((length(address)>20) and (address[1] = 'N')) then + if length(Address) < 1 then exit; + FirstChar := address[1]; + if ((length(address)>20) and ((address[1] = 'N') or (address[1] = 'M')) ) then begin OrigHash := Copy(Address,2,length(address)-3); if IsValid58(OrigHash) then - if 'N'+OrigHash+(B10toB58(BMB58resumen(OrigHash))) = Address then + if FirstChar+OrigHash+(B10toB58(BMB58resumen(OrigHash))) = Address then result := true; end End; @@ -430,6 +437,66 @@ function GetOrderHash(TextLine:string):String; Result := Resultado; End; + +//getmulti 1,2 N31ThXmSR2gua5tfCFNLEkYK9yNQsDi,N31ThXmSR2gua5tfCFNLEkYK9yNQsDi +Function GetMultiSource(Source: String;AddsTotal:integer;Out OrderedSource:String) : boolean; +var + Addresses : array of string; + Counter : integer = 0; + Counter2 : integer = 0; + ThisSour : string; + Inserted : boolean = false; + LocSource : string; + Existing : string = ''; +Begin + Result := false; + OrderedSource := ''; + LocSource := StringReplace(Source,',',' ',[rfReplaceAll, rfIgnoreCase]); + SetLength(Addresses,0); + Repeat + Inserted := false; + ThisSour := Parameter(LocSource,counter); + if thisSour <> '' then + begin + if AnsiContainsStr(Existing,ThisSour) then + begin + OrderedSource:= 'Duplicated address -> '+ThisSour; + Exit; + end; + Existing := Existing+','+thisSour; + if not IsValidHashAddress(ThisSour) then + begin + OrderedSource:= 'Invalid hash address -> '+ThisSour; + Exit; + end; + if length(Addresses) = 0 then Insert(ThisSour,Addresses,0) + else + begin + For counter2 := 0 to length(addresses)-1 do + begin + if ThisSour < Addresses[counter2] then + begin + Insert(ThisSour,Addresses,counter2); + Inserted := true; + end; + end; + if not inserted then Insert(ThisSour,Addresses,length(Addresses)); + end; + end; + Inc(Counter); + until ( (ThisSour = '') or (Counter = AddsTotal) ); + if length(Addresses) <> AddsTotal then OrderedSource:= format('Wrong addresses count %d/%d',[length(addresses),AddsTotal]); + if OrderedSource = '' then + begin + for counter := 0 to length(Addresses)-1 do + Begin + OrderedSource := OrderedSource+Addresses[counter]; + if counter < LEngth(addresses)-1 then OrderedSource := OrderedSource+','; + end; + Result := true; + end; +End; + {** New base conversion functions **} Function TrimLeadingCeros(const S: String): String; Begin diff --git a/nosogeneral.pas b/nosogeneral.pas index 2cce9d7..cd6dfec 100644 --- a/nosogeneral.pas +++ b/nosogeneral.pas @@ -40,6 +40,22 @@ TStreamHelper = class helper for TStream TrfrID : String[64]; end; + + TMultiOrder = record + Block : integer; + TimeStamp : Int64; + OrderID : string[64]; + OrderType : String[6]; + Reference : String[64]; + sender : String[40]; + PubKey : String[255]; + Receiver : String[40]; + Signer : string[120]; + Signature : string[120]; + AmmountFee : Int64; + AmmountTrf : Int64; + end; + TBlockOrdersArray = Array of TOrderData; {Generic} @@ -52,6 +68,7 @@ TStreamHelper = class helper for TStream Function HashrateToShow(speed:int64):String; Function Int2Curr(LValue: int64): string; Procedure RunExternalProgram(ProgramToRun:String); +Function GetCustFee(Block:integer):int64; Function GetStackRequired(block:integer):int64; Function GetMNsPercentage(block:integer;MainnetMode:String='NORMAL'):integer; Function GetPoSPercentage(block:integer):integer; @@ -257,6 +274,13 @@ function TStreamHelper.GetString: String; Process.Free; End; +{Returns the custom fee amount} +Function GetCustFee(Block:integer):int64; +Begin + result := 1000000; + if block < 162000 then result := 25000; +End; + {Returns the required noso stack size} Function GetStackRequired(block:integer):int64; Begin diff --git a/nosonetwork.pas b/nosonetwork.pas index 6dc4f1a..3e945a2 100644 --- a/nosonetwork.pas +++ b/nosonetwork.pas @@ -144,6 +144,7 @@ NodeServerEvents = class ArrayOutgoing : array [1..MaxConecciones] of array of string; BotsList : array of TBotData; ArrayPoolTXs : Array of TOrderData; + ArrayMultiTXs : Array of TMultiOrder; // Donwloading files DownloadHeaders : boolean = false; DownloadSumary : Boolean = false; @@ -347,6 +348,10 @@ function TrxExistsInLastBlock(trfrhash:String):boolean; {$ENDREGION Pending Pool transactions} +{$REGION Pending Multi transactions} + +{$ENDREGION} + {$REGION Protocol} // Returns protocolo message header @@ -1463,6 +1468,7 @@ function BotExists(IPUser:String):Boolean; InitCriticalSection(CSNodesList); SetLength(BotsList,0); Setlength(ArrayPoolTXs,0); + SetLength(ArrayMultiTXs,0); Setlength(NodesList,0); for counter := 1 to MaxConecciones do begin