├── .gitignore ├── BitcoinBlockChainExplorer.dpr ├── BitcoinBlockChainExplorer.dproj ├── BitcoinBlockChainExplorer.res ├── BlocksUnit.pas ├── CryptoVirtualTreeUnit.pas ├── LICENSE ├── MainFormUnit.dfm ├── MainFormUnit.pas ├── README.md ├── SeSHA256.pas ├── ThreadUnit.pas ├── asm.inc ├── datamodule.dfm ├── datamodule.pas └── sample-config.ini /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | #*.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | 53 | # Delphi local files (user-specific info) 54 | *.local 55 | *.identcache 56 | *.projdata 57 | *.tvsconfig 58 | *.dsk 59 | 60 | # Delphi history and backups 61 | __history/ 62 | __recovery/ 63 | *.~* 64 | 65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 66 | *.stat 67 | Win32/Debug/config.ini 68 | config.ini 69 | -------------------------------------------------------------------------------- /BitcoinBlockChainExplorer.dpr: -------------------------------------------------------------------------------- 1 | program BitcoinBlockChainExplorer; 2 | 3 | uses 4 | Vcl.Forms, 5 | MainFormUnit in 'MainFormUnit.pas' {MainForm}, 6 | BlocksUnit in 'BlocksUnit.pas', 7 | SeSHA256 in 'SeSHA256.pas', 8 | ThreadUnit in 'ThreadUnit.pas'; 9 | 10 | {$R *.res} 11 | 12 | begin 13 | Application.Initialize; 14 | Application.MainFormOnTaskbar := True; 15 | Application.CreateForm(TMainForm, MainForm); 16 | Application.Run; 17 | 18 | end. 19 | -------------------------------------------------------------------------------- /BitcoinBlockChainExplorer.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {8C8DBE02-69FF-4E27-B31A-0D5AE8768554} 4 | 19.2 5 | VCL 6 | BitcoinBlockChainExplorer.dpr 7 | True 8 | Debug 9 | Win32 10 | 1 11 | Application 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Cfg_1 40 | true 41 | true 42 | 43 | 44 | true 45 | Base 46 | true 47 | 48 | 49 | true 50 | Cfg_2 51 | true 52 | true 53 | 54 | 55 | true 56 | Cfg_2 57 | true 58 | true 59 | 60 | 61 | .\$(Platform)\$(Config) 62 | .\$(Platform)\$(Config) 63 | false 64 | false 65 | false 66 | false 67 | false 68 | RESTComponents;FireDAC;FireDACSqliteDriver;soaprtl;FireDACIBDriver;soapmidas;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;$(DCC_UsePackage) 69 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 70 | $(BDS)\bin\delphi_PROJECTICON.ico 71 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 72 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 73 | BitcoinBlockChainExplorer 74 | 75 | 76 | DBXSqliteDriver;IndyIPCommon;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;vcltouch;vcldb;bindcompfmx;svn;FireDACPgDriver;inetdb;DbxCommonDriver;fmx;fmxdae;xmlrtl;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;IndyIPClient;bindcompvcl;VCLRESTComponents;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;fmxase;$(DCC_UsePackage) 77 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 78 | Debug 79 | true 80 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 81 | 1033 82 | $(BDS)\bin\default_app.manifest 83 | 84 | 85 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 86 | Debug 87 | true 88 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 89 | 1033 90 | $(BDS)\bin\default_app.manifest 91 | 92 | 93 | DEBUG;$(DCC_Define) 94 | true 95 | false 96 | true 97 | true 98 | true 99 | 100 | 101 | false 102 | true 103 | PerMonitor 104 | 105 | 106 | true 107 | PerMonitorV2 108 | 109 | 110 | false 111 | RELEASE;$(DCC_Define) 112 | 0 113 | 0 114 | 115 | 116 | true 117 | PerMonitor 118 | 119 | 120 | true 121 | PerMonitorV2 122 | 123 | 124 | 125 | MainSource 126 | 127 | 128 |
MainForm
129 | dfm 130 |
131 | 132 | 133 | 134 | 135 | 136 | Cfg_2 137 | Base 138 | 139 | 140 | Base 141 | 142 | 143 | Cfg_1 144 | Base 145 | 146 |
147 | 148 | Delphi.Personality.12 149 | Application 150 | 151 | 152 | 153 | BitcoinBlockChainExplorer.dpr 154 | 155 | 156 | 157 | 158 | 159 | BitcoinBlockChainExplorer.exe 160 | true 161 | 162 | 163 | 164 | 165 | .\ 166 | true 167 | 168 | 169 | 170 | 171 | 1 172 | 173 | 174 | Contents\MacOS 175 | 1 176 | 177 | 178 | 0 179 | 180 | 181 | 182 | 183 | classes 184 | 1 185 | 186 | 187 | classes 188 | 1 189 | 190 | 191 | 192 | 193 | res\xml 194 | 1 195 | 196 | 197 | res\xml 198 | 1 199 | 200 | 201 | 202 | 203 | library\lib\armeabi-v7a 204 | 1 205 | 206 | 207 | 208 | 209 | library\lib\armeabi 210 | 1 211 | 212 | 213 | library\lib\armeabi 214 | 1 215 | 216 | 217 | 218 | 219 | library\lib\armeabi-v7a 220 | 1 221 | 222 | 223 | 224 | 225 | library\lib\mips 226 | 1 227 | 228 | 229 | library\lib\mips 230 | 1 231 | 232 | 233 | 234 | 235 | library\lib\armeabi-v7a 236 | 1 237 | 238 | 239 | library\lib\arm64-v8a 240 | 1 241 | 242 | 243 | 244 | 245 | library\lib\armeabi-v7a 246 | 1 247 | 248 | 249 | 250 | 251 | res\drawable 252 | 1 253 | 254 | 255 | res\drawable 256 | 1 257 | 258 | 259 | 260 | 261 | res\values 262 | 1 263 | 264 | 265 | res\values 266 | 1 267 | 268 | 269 | 270 | 271 | res\values-v21 272 | 1 273 | 274 | 275 | res\values-v21 276 | 1 277 | 278 | 279 | 280 | 281 | res\values 282 | 1 283 | 284 | 285 | res\values 286 | 1 287 | 288 | 289 | 290 | 291 | res\drawable 292 | 1 293 | 294 | 295 | res\drawable 296 | 1 297 | 298 | 299 | 300 | 301 | res\drawable-xxhdpi 302 | 1 303 | 304 | 305 | res\drawable-xxhdpi 306 | 1 307 | 308 | 309 | 310 | 311 | res\drawable-xxxhdpi 312 | 1 313 | 314 | 315 | res\drawable-xxxhdpi 316 | 1 317 | 318 | 319 | 320 | 321 | res\drawable-ldpi 322 | 1 323 | 324 | 325 | res\drawable-ldpi 326 | 1 327 | 328 | 329 | 330 | 331 | res\drawable-mdpi 332 | 1 333 | 334 | 335 | res\drawable-mdpi 336 | 1 337 | 338 | 339 | 340 | 341 | res\drawable-hdpi 342 | 1 343 | 344 | 345 | res\drawable-hdpi 346 | 1 347 | 348 | 349 | 350 | 351 | res\drawable-xhdpi 352 | 1 353 | 354 | 355 | res\drawable-xhdpi 356 | 1 357 | 358 | 359 | 360 | 361 | res\drawable-mdpi 362 | 1 363 | 364 | 365 | res\drawable-mdpi 366 | 1 367 | 368 | 369 | 370 | 371 | res\drawable-hdpi 372 | 1 373 | 374 | 375 | res\drawable-hdpi 376 | 1 377 | 378 | 379 | 380 | 381 | res\drawable-xhdpi 382 | 1 383 | 384 | 385 | res\drawable-xhdpi 386 | 1 387 | 388 | 389 | 390 | 391 | res\drawable-xxhdpi 392 | 1 393 | 394 | 395 | res\drawable-xxhdpi 396 | 1 397 | 398 | 399 | 400 | 401 | res\drawable-xxxhdpi 402 | 1 403 | 404 | 405 | res\drawable-xxxhdpi 406 | 1 407 | 408 | 409 | 410 | 411 | res\drawable-small 412 | 1 413 | 414 | 415 | res\drawable-small 416 | 1 417 | 418 | 419 | 420 | 421 | res\drawable-normal 422 | 1 423 | 424 | 425 | res\drawable-normal 426 | 1 427 | 428 | 429 | 430 | 431 | res\drawable-large 432 | 1 433 | 434 | 435 | res\drawable-large 436 | 1 437 | 438 | 439 | 440 | 441 | res\drawable-xlarge 442 | 1 443 | 444 | 445 | res\drawable-xlarge 446 | 1 447 | 448 | 449 | 450 | 451 | res\values 452 | 1 453 | 454 | 455 | res\values 456 | 1 457 | 458 | 459 | 460 | 461 | 1 462 | 463 | 464 | Contents\MacOS 465 | 1 466 | 467 | 468 | 0 469 | 470 | 471 | 472 | 473 | Contents\MacOS 474 | 1 475 | .framework 476 | 477 | 478 | Contents\MacOS 479 | 1 480 | .framework 481 | 482 | 483 | 0 484 | 485 | 486 | 487 | 488 | 1 489 | .dylib 490 | 491 | 492 | 1 493 | .dylib 494 | 495 | 496 | 1 497 | .dylib 498 | 499 | 500 | Contents\MacOS 501 | 1 502 | .dylib 503 | 504 | 505 | Contents\MacOS 506 | 1 507 | .dylib 508 | 509 | 510 | 0 511 | .dll;.bpl 512 | 513 | 514 | 515 | 516 | 1 517 | .dylib 518 | 519 | 520 | 1 521 | .dylib 522 | 523 | 524 | 1 525 | .dylib 526 | 527 | 528 | Contents\MacOS 529 | 1 530 | .dylib 531 | 532 | 533 | Contents\MacOS 534 | 1 535 | .dylib 536 | 537 | 538 | 0 539 | .bpl 540 | 541 | 542 | 543 | 544 | 0 545 | 546 | 547 | 0 548 | 549 | 550 | 0 551 | 552 | 553 | 0 554 | 555 | 556 | 0 557 | 558 | 559 | Contents\Resources\StartUp\ 560 | 0 561 | 562 | 563 | Contents\Resources\StartUp\ 564 | 0 565 | 566 | 567 | 0 568 | 569 | 570 | 571 | 572 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 573 | 1 574 | 575 | 576 | 577 | 578 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 579 | 1 580 | 581 | 582 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 583 | 1 584 | 585 | 586 | 587 | 588 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 589 | 1 590 | 591 | 592 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 593 | 1 594 | 595 | 596 | 597 | 598 | 1 599 | 600 | 601 | 1 602 | 603 | 604 | 1 605 | 606 | 607 | 608 | 609 | 1 610 | 611 | 612 | 1 613 | 614 | 615 | 1 616 | 617 | 618 | 619 | 620 | 1 621 | 622 | 623 | 1 624 | 625 | 626 | 1 627 | 628 | 629 | 630 | 631 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 632 | 1 633 | 634 | 635 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 636 | 1 637 | 638 | 639 | 640 | 641 | 1 642 | 643 | 644 | 1 645 | 646 | 647 | 1 648 | 649 | 650 | 651 | 652 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 653 | 1 654 | 655 | 656 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 657 | 1 658 | 659 | 660 | 661 | 662 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 663 | 1 664 | 665 | 666 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 667 | 1 668 | 669 | 670 | 671 | 672 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 673 | 1 674 | 675 | 676 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 677 | 1 678 | 679 | 680 | 681 | 682 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 683 | 1 684 | 685 | 686 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 687 | 1 688 | 689 | 690 | 691 | 692 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 693 | 1 694 | 695 | 696 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 697 | 1 698 | 699 | 700 | 701 | 702 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 703 | 1 704 | 705 | 706 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 707 | 1 708 | 709 | 710 | 711 | 712 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 713 | 1 714 | 715 | 716 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 717 | 1 718 | 719 | 720 | 721 | 722 | 1 723 | 724 | 725 | 1 726 | 727 | 728 | 1 729 | 730 | 731 | 732 | 733 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 734 | 1 735 | 736 | 737 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 738 | 1 739 | 740 | 741 | 742 | 743 | 1 744 | 745 | 746 | 1 747 | 748 | 749 | 1 750 | 751 | 752 | 753 | 754 | 1 755 | 756 | 757 | 1 758 | 759 | 760 | 1 761 | 762 | 763 | 764 | 765 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 766 | 1 767 | 768 | 769 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 770 | 1 771 | 772 | 773 | 774 | 775 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 776 | 1 777 | 778 | 779 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 780 | 1 781 | 782 | 783 | 784 | 785 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 786 | 1 787 | 788 | 789 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 790 | 1 791 | 792 | 793 | 794 | 795 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 796 | 1 797 | 798 | 799 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 800 | 1 801 | 802 | 803 | 804 | 805 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 806 | 1 807 | 808 | 809 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 810 | 1 811 | 812 | 813 | 814 | 815 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 816 | 1 817 | 818 | 819 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 820 | 1 821 | 822 | 823 | 824 | 825 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 826 | 1 827 | 828 | 829 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 830 | 1 831 | 832 | 833 | 834 | 835 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 836 | 1 837 | 838 | 839 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 840 | 1 841 | 842 | 843 | 844 | 845 | 1 846 | 847 | 848 | 1 849 | 850 | 851 | 852 | 853 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 854 | 1 855 | 856 | 857 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 858 | 1 859 | 860 | 861 | 862 | 863 | 1 864 | 865 | 866 | 1 867 | 868 | 869 | 870 | 871 | ..\ 872 | 1 873 | 874 | 875 | ..\ 876 | 1 877 | 878 | 879 | 880 | 881 | 1 882 | 883 | 884 | 1 885 | 886 | 887 | 1 888 | 889 | 890 | 891 | 892 | ..\$(PROJECTNAME).launchscreen 893 | 64 894 | 895 | 896 | ..\$(PROJECTNAME).launchscreen 897 | 64 898 | 899 | 900 | 901 | 902 | 1 903 | 904 | 905 | 1 906 | 907 | 908 | 1 909 | 910 | 911 | 912 | 913 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 914 | 1 915 | 916 | 917 | 918 | 919 | ..\ 920 | 1 921 | 922 | 923 | ..\ 924 | 1 925 | 926 | 927 | 928 | 929 | Contents 930 | 1 931 | 932 | 933 | Contents 934 | 1 935 | 936 | 937 | 938 | 939 | Contents\Resources 940 | 1 941 | 942 | 943 | Contents\Resources 944 | 1 945 | 946 | 947 | 948 | 949 | library\lib\armeabi-v7a 950 | 1 951 | 952 | 953 | library\lib\arm64-v8a 954 | 1 955 | 956 | 957 | 1 958 | 959 | 960 | 1 961 | 962 | 963 | 1 964 | 965 | 966 | 1 967 | 968 | 969 | Contents\MacOS 970 | 1 971 | 972 | 973 | Contents\MacOS 974 | 1 975 | 976 | 977 | 0 978 | 979 | 980 | 981 | 982 | library\lib\armeabi-v7a 983 | 1 984 | 985 | 986 | 987 | 988 | 1 989 | 990 | 991 | 1 992 | 993 | 994 | 995 | 996 | Assets 997 | 1 998 | 999 | 1000 | Assets 1001 | 1 1002 | 1003 | 1004 | 1005 | 1006 | Assets 1007 | 1 1008 | 1009 | 1010 | Assets 1011 | 1 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | True 1027 | False 1028 | 1029 | 1030 | 12 1031 | 1032 | 1033 | 1034 | 1035 |
1036 | -------------------------------------------------------------------------------- /BitcoinBlockChainExplorer.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ildemartinez/Delphi-Component-for-BlockChain-Dat-Files/2e01557fd4537d9375bd148183134b34bf8e9b5f/BitcoinBlockChainExplorer.res -------------------------------------------------------------------------------- /BlocksUnit.pas: -------------------------------------------------------------------------------- 1 | unit BlocksUnit; 2 | 3 | interface 4 | 5 | uses 6 | System.Classes, 7 | System.Contnrs, 8 | Generics.Collections, 9 | 10 | SeSHA256; 11 | 12 | type 13 | TCrypto = (tcBitcoin); 14 | TNet = (tnMainNet, tnTestNet); 15 | 16 | TBlockChainFiles = class; 17 | 18 | TBlockFile = class(TObject) 19 | parent: TBlockChainFiles; 20 | aFileName: string; 21 | aBlockNumber: integer; 22 | afs: TBufferedFileStream; 23 | end; 24 | 25 | TBlockChainFiles = class(TList) 26 | 27 | end; 28 | 29 | TBlockHeader = record 30 | versionNumber: UInt32; 31 | aPreviousBlockHash: T32; // reverse please 32 | aMerkleRoot: T32; // reverse please 33 | time: UInt32; // UnixTime 34 | DifficultyTarget: UInt32; 35 | nonce: UInt32; 36 | end; 37 | 38 | TInput = class(TObject) 39 | aTXID: T32; 40 | aVOUT: UInt32; 41 | CoinBaseLength: uint64; 42 | CoinBase: PByte; 43 | 44 | destructor Destroy; override; 45 | end; 46 | 47 | TOutput = class(TObject) 48 | nValue: uint64; 49 | OutputScriptLength: uint64; 50 | OutputScript: PByte; 51 | 52 | destructor Destroy; override; 53 | end; 54 | 55 | TInputs = class(TObjectList) 56 | private 57 | function GetInput(index: integer): TInput; 58 | public 59 | function NewInput: TInput; 60 | property items[index: integer]: TInput read GetInput; default; 61 | end; 62 | 63 | TOutputs = class(TObjectList) 64 | private 65 | function GetOutput(index: integer): TOutput; 66 | public 67 | function NewOutput: TOutput; 68 | property items[index: integer]: TOutput read GetOutput; default; 69 | end; 70 | 71 | TTransaction = class(TObject) 72 | version: UInt32; 73 | inputs: TInputs; 74 | outputs: TOutputs; 75 | 76 | public 77 | constructor Create; 78 | destructor Destroy; override; 79 | end; 80 | 81 | TBlockTransactions = class(TObjectList) 82 | private 83 | function GetTransaction(index: integer): TTransaction; 84 | public 85 | function NewTransaction: TTransaction; 86 | property items[index: integer]: TTransaction read GetTransaction; default; 87 | end; 88 | 89 | TBlockRecord = class(TObject) 90 | nblock: uint64; 91 | blocktype: TCrypto; 92 | network: TNet; 93 | 94 | headerLenght: UInt32; 95 | hash: string; 96 | header: TBlockHeader; 97 | transactions: TBlockTransactions; 98 | 99 | ninputs, noutputs: uint64; 100 | 101 | public 102 | constructor Create; 103 | destructor Destroy; override; 104 | end; 105 | 106 | TStartFileBlockFoundNotify = procedure(const aBlockFiles: TList) of object; 107 | TFoundFileBlockNotify = procedure(const aBlockFile: TBlockFile; var next: boolean) of object; 108 | TEndFilesBlockFoundNotify = procedure(const aBlockFiles: tstringlist) of object; 109 | 110 | TFoundBlockNotify = procedure(const aBlock: TBlockRecord; var findnext: boolean) of object; 111 | TBlockProcessStepNotify = procedure(const aPos, asize: int64) of object; 112 | 113 | TBlocks = class(tthread) 114 | private 115 | // File block events 116 | fOnStartProcessFiles: TStartFileBlockFoundNotify; 117 | fOnAfterFileBlockProcessed: TFoundFileBlockNotify; 118 | 119 | fOnMagicBlockFound: TFoundBlockNotify; 120 | fBlockProcessStep: TBlockProcessStepNotify; 121 | // fEndProcessBlockFile: TEndProcessBlockFile; 122 | fOnEndProc: TNotifyEvent; 123 | fOnStartProc: TNotifyEvent; 124 | fOnBeforeFileBlockProcess: TFoundFileBlockNotify; 125 | 126 | procedure InternalProcessBlock(const aBlockFile: TBlockFile); 127 | public 128 | aBlockChainFiles: TBlockChainFiles; 129 | BlocksDir: string; 130 | aBlocksDirectory: string; 131 | 132 | procedure Execute; override; 133 | 134 | // Inicio y fin del parseo 135 | property OnStartingParsingBlockfiles: TNotifyEvent read fOnStartProc write fOnStartProc; 136 | property OnFinishedParsingBlockFiles: TNotifyEvent read fOnEndProc write fOnEndProc; 137 | 138 | // Start process all files 139 | property OnStartProcessFiles: TStartFileBlockFoundNotify read fOnStartProcessFiles write fOnStartProcessFiles; 140 | 141 | // before process a file 142 | property OnBeforeFileBlockProcess: TFoundFileBlockNotify read fOnBeforeFileBlockProcess write fOnBeforeFileBlockProcess; 143 | 144 | // after a processed file 145 | property OnAfterFileBlockProcessed: TFoundFileBlockNotify read fOnAfterFileBlockProcessed write fOnAfterFileBlockProcessed; 146 | 147 | // Block found 148 | property OnMagicBlockFound: TFoundBlockNotify read fOnMagicBlockFound write fOnMagicBlockFound; 149 | 150 | property OnBlockProcessStep: TBlockProcessStepNotify read fBlockProcessStep write fBlockProcessStep; 151 | end; 152 | 153 | implementation 154 | 155 | uses 156 | WinApi.Windows, 157 | SysUtils, dialogs, dateutils, 158 | MainFormUnit, System.hash, 159 | inifiles; 160 | 161 | procedure TBlocks.Execute; 162 | var 163 | searchResult: TSearchRec; 164 | aBlockFile: TBlockFile; 165 | 166 | aBlockFiles: TList; 167 | aBlockFil: string; 168 | 169 | next: boolean; 170 | files: string; 171 | begin 172 | 173 | aBlockChainFiles := TBlockChainFiles.Create; 174 | 175 | // Start parsing component 176 | if Assigned(OnStartingParsingBlockfiles) then 177 | Synchronize( 178 | procedure 179 | begin 180 | OnStartingParsingBlockfiles(self); 181 | end); 182 | 183 | SetCurrentDir(aBlocksDirectory); 184 | 185 | files := 'blk?????.dat'; 186 | // files := 'blk00074.dat'; 187 | 188 | if findfirst(files, faAnyFile, searchResult) = 0 then 189 | begin 190 | aBlockFiles := TList.Create; 191 | 192 | repeat 193 | aBlockFiles.Add(aBlocksDirectory + '\' + searchResult.Name); 194 | until findnext(searchResult) <> 0; 195 | 196 | // Must free up resources used by these successful finds 197 | System.SysUtils.FindClose(searchResult); 198 | 199 | // Start parsing all files 200 | if Assigned(OnStartProcessFiles) then 201 | Synchronize( 202 | procedure 203 | begin 204 | OnStartProcessFiles(aBlockFiles); 205 | end); 206 | 207 | for aBlockFil in aBlockFiles do 208 | begin 209 | 210 | aBlockFile := TBlockFile.Create; 211 | aBlockFile.parent := aBlockChainFiles; 212 | aBlockChainFiles.Add(aBlockFile); 213 | aBlockFile.aFileName := aBlockFil; 214 | aBlockFile.aBlockNumber := aBlockFiles.IndexOf(aBlockFil) + 1; 215 | 216 | // Start parsing a file 217 | if Assigned(fOnBeforeFileBlockProcess) then 218 | Synchronize( 219 | procedure 220 | begin 221 | fOnBeforeFileBlockProcess(aBlockFile, next); 222 | end); 223 | 224 | aBlockFile.afs := TBufferedFileStream.Create(aBlockFile.aFileName, fmOpenRead); 225 | try 226 | InternalProcessBlock(aBlockFile); 227 | finally 228 | aBlockFile.afs.Free; 229 | end; 230 | 231 | if Assigned(OnAfterFileBlockProcessed) then 232 | Synchronize( 233 | procedure 234 | begin 235 | OnAfterFileBlockProcessed(aBlockFile, next); 236 | end); 237 | 238 | aBlockFile.Free; 239 | 240 | if next = false then 241 | break; 242 | end; 243 | 244 | aBlockFiles.Free; 245 | end; 246 | 247 | if Assigned(OnFinishedParsingBlockFiles) then 248 | Synchronize( 249 | procedure 250 | begin 251 | OnFinishedParsingBlockFiles(self); 252 | end); 253 | end; 254 | 255 | procedure TBlocks.InternalProcessBlock(const aBlockFile: TBlockFile); 256 | var 257 | state, car: byte; 258 | aBlock: TBlockRecord; 259 | cont: boolean; 260 | aTransaction: TTransaction; 261 | aseq: longword; 262 | aInput: TInput; 263 | aOutput: TOutput; 264 | 265 | tb: THeader; 266 | var 267 | alocktime: UInt32; 268 | txCount, k: uint64; 269 | 270 | function ReadVarValue: uint64; 271 | var 272 | atxCount: UInt8; 273 | atxCount2: UInt16; 274 | atxCount4: UInt32; 275 | begin 276 | aBlockFile.afs.Read(atxCount, 1); 277 | if atxCount < $FD then 278 | result := atxCount 279 | else 280 | case atxCount of 281 | $FD: 282 | begin 283 | aBlockFile.afs.Read(atxCount2, 2); 284 | result := atxCount2; 285 | end; 286 | $FE: 287 | begin 288 | aBlockFile.afs.Read(atxCount4, 4); 289 | result := atxCount4; 290 | end; 291 | $FF: 292 | aBlockFile.afs.Read(result, 8); 293 | end; 294 | 295 | end; 296 | 297 | begin 298 | state := 0; 299 | cont := true; 300 | 301 | while (cont = true) and (aBlockFile.afs.Read(car, 1) = 1) do 302 | begin 303 | 304 | case state of 305 | 0: 306 | if car = $F9 then 307 | inc(state); 308 | 1: 309 | if car = $BE then 310 | inc(state) 311 | else 312 | state := 0; 313 | 2: 314 | if car = $B4 then 315 | inc(state) 316 | else 317 | state := 0; 318 | 3: 319 | if car = $D9 then 320 | begin 321 | 322 | if Assigned(OnBlockProcessStep) then 323 | Synchronize( 324 | procedure 325 | begin 326 | OnBlockProcessStep(aBlockFile.afs.Position, aBlockFile.afs.Size); 327 | end); 328 | 329 | aBlock := TBlockRecord.Create; 330 | 331 | aBlockFile.afs.Read(aBlock.headerLenght, 4); 332 | 333 | // Read the header fields 334 | aBlockFile.afs.Read(aBlock.header, HEADERSIZE); 335 | 336 | // Re-read the header to calculate hash 337 | aBlockFile.afs.Seek(-HEADERSIZE, soCurrent); 338 | aBlockFile.afs.Read(tb, HEADERSIZE); 339 | 340 | // double header hash 341 | aBlock.hash := reversehash(SHA256ToStr(CalcSHA256(SHA256ToBinaryStr(CalcHeaderSHA256(tb))))); 342 | 343 | // tx count 344 | txCount := ReadVarValue; 345 | 346 | while (txCount > 0) do 347 | begin 348 | aTransaction := aBlock.transactions.NewTransaction; 349 | 350 | // Read the transaction version 351 | aBlockFile.afs.Read(aTransaction.version, 4); 352 | // Read the inputs 353 | aBlock.ninputs := ReadVarValue; 354 | 355 | if aBlock.ninputs > 0 then 356 | for k := 0 to aBlock.ninputs - 1 do 357 | begin 358 | aInput := aTransaction.inputs.NewInput; 359 | 360 | aBlockFile.afs.Read(aInput.aTXID, 32); 361 | aBlockFile.afs.Read(aInput.aVOUT, 4); 362 | 363 | aInput.CoinBaseLength := ReadVarValue; 364 | 365 | GetMem(aInput.CoinBase, aInput.CoinBaseLength); 366 | aBlockFile.afs.Read(aInput.CoinBase^, aInput.CoinBaseLength); 367 | 368 | // No need store the seq 369 | aBlockFile.afs.Read(aseq, 4); 370 | end; 371 | 372 | // tx out count 373 | aBlock.noutputs := ReadVarValue; 374 | 375 | if aBlock.noutputs > 0 then 376 | for k := 0 to aBlock.noutputs - 1 do 377 | begin 378 | aOutput := aTransaction.outputs.NewOutput; 379 | 380 | aBlockFile.afs.Read(aOutput.nValue, 8); // in satoshis 381 | 382 | aOutput.OutputScriptLength := ReadVarValue; 383 | 384 | GetMem(aOutput.OutputScript, aOutput.OutputScriptLength); 385 | aBlockFile.afs.Read(aOutput.OutputScript^, aOutput.OutputScriptLength); 386 | end; 387 | 388 | aBlockFile.afs.Read(alocktime, 4); 389 | dec(txCount); 390 | end; 391 | 392 | // Fire the block found event 393 | if Assigned(OnMagicBlockFound) then 394 | Synchronize( 395 | procedure 396 | begin 397 | OnMagicBlockFound(aBlock, cont); 398 | end); 399 | 400 | // Free the block so user must copy or use it and forget 401 | aBlock.Free; 402 | 403 | state := 0; 404 | end; 405 | 406 | end; 407 | 408 | end; 409 | 410 | end; 411 | 412 | { TBlockRecord } 413 | 414 | constructor TBlockRecord.Create; 415 | begin 416 | transactions := TBlockTransactions.Create; 417 | end; 418 | 419 | destructor TBlockRecord.Destroy; 420 | begin 421 | transactions.Free; 422 | 423 | inherited; 424 | end; 425 | 426 | { TBlockTransactions } 427 | 428 | function TBlockTransactions.GetTransaction(index: integer): TTransaction; 429 | begin 430 | result := inherited items[index] as TTransaction; 431 | end; 432 | 433 | function TBlockTransactions.NewTransaction: TTransaction; 434 | begin 435 | result := TTransaction.Create; 436 | self.Add(result); 437 | end; 438 | 439 | { TTransaction } 440 | 441 | constructor TTransaction.Create; 442 | begin 443 | inputs := TInputs.Create; 444 | outputs := TOutputs.Create; 445 | end; 446 | 447 | destructor TTransaction.Destroy; 448 | begin 449 | inputs.Free; 450 | outputs.Free; 451 | end; 452 | 453 | { TOutputs } 454 | 455 | function TOutputs.GetOutput(index: integer): TOutput; 456 | begin 457 | result := TOutput(inherited items[index]); 458 | end; 459 | 460 | function TOutputs.NewOutput: TOutput; 461 | begin 462 | result := TOutput.Create; 463 | self.Add(result); 464 | end; 465 | 466 | { TInputs } 467 | 468 | function TInputs.GetInput(index: integer): TInput; 469 | begin 470 | result := TInput(inherited items[index]); 471 | end; 472 | 473 | function TInputs.NewInput: TInput; 474 | begin 475 | result := TInput.Create; 476 | self.Add(result); 477 | end; 478 | 479 | destructor TInput.Destroy; 480 | begin 481 | FreeMem(CoinBase); 482 | 483 | inherited; 484 | end; 485 | 486 | destructor TOutput.Destroy; 487 | begin 488 | FreeMem(OutputScript); 489 | 490 | inherited; 491 | end; 492 | 493 | end. 494 | -------------------------------------------------------------------------------- /CryptoVirtualTreeUnit.pas: -------------------------------------------------------------------------------- 1 | unit CryptoVirtualTreeUnit; 2 | 3 | interface 4 | 5 | uses 6 | System.Classes, virtualtrees; 7 | 8 | type 9 | TCryptoVirtualTree = class(TCustomVirtualStringTree) 10 | 11 | public 12 | constructor Create(AOwner: TComponent); override; 13 | end; 14 | 15 | implementation 16 | 17 | { TCryptoVirtualTree } 18 | 19 | constructor TCryptoVirtualTree.Create(AOwner: TComponent); 20 | var 21 | aNode: PVirtualNode; 22 | begin 23 | inherited; 24 | 25 | aNode := self.AddChild(nil); 26 | 27 | AddChild(aNode); 28 | AddChild(aNode); 29 | AddChild(aNode); 30 | AddChild(aNode); 31 | 32 | end; 33 | 34 | end. 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Software Tools for Makers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MainFormUnit.dfm: -------------------------------------------------------------------------------- 1 | object MainForm: TMainForm 2 | Left = 0 3 | Top = 0 4 | Caption = 'CryptoLab' 5 | ClientHeight = 665 6 | ClientWidth = 1211 7 | Color = clBtnFace 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | FormStyle = fsMDIForm 14 | OldCreateOrder = False 15 | OnCreate = FormCreate 16 | PixelsPerInch = 96 17 | TextHeight = 13 18 | object Memo1: TMemo 19 | Left = 104 20 | Top = 31 21 | Width = 770 22 | Height = 337 23 | Font.Charset = DEFAULT_CHARSET 24 | Font.Color = clWindowText 25 | Font.Height = -9 26 | Font.Name = 'Tahoma' 27 | Font.Style = [] 28 | ParentFont = False 29 | TabOrder = 0 30 | end 31 | object Button2: TButton 32 | Left = 48 33 | Top = 374 34 | Width = 75 35 | Height = 25 36 | Caption = 'Button2' 37 | TabOrder = 1 38 | OnClick = Button2Click 39 | end 40 | object Button1: TButton 41 | Left = 368 42 | Top = 424 43 | Width = 75 44 | Height = 25 45 | Caption = 'Button1' 46 | TabOrder = 2 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /MainFormUnit.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ildemartinez/Delphi-Component-for-BlockChain-Dat-Files/2e01557fd4537d9375bd148183134b34bf8e9b5f/MainFormUnit.pas -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Delphi Component for Bitcoin BlockChain parse Dat Files 2 | This is a Delphi component for reading the dat files from Blockchain. The idea is a high performance event driven component to parse blockchain files from several criptocurrencies. Lets start with the Bitcoin one! 3 | 4 | Here is released the component and the application to test it..... on dev process of course! 5 | 6 | Hashing sha256 functions from https://github.com/dxeoane/secrypt 7 | -------------------------------------------------------------------------------- /SeSHA256.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ildemartinez/Delphi-Component-for-BlockChain-Dat-Files/2e01557fd4537d9375bd148183134b34bf8e9b5f/SeSHA256.pas -------------------------------------------------------------------------------- /ThreadUnit.pas: -------------------------------------------------------------------------------- 1 | unit ThreadUnit; 2 | 3 | interface 4 | 5 | implementation 6 | 7 | end. 8 | -------------------------------------------------------------------------------- /asm.inc: -------------------------------------------------------------------------------- 1 | {$IFDEF i386} 2 | 3 | {$IFDEF FPC} 4 | {$ASMMODE intel} 5 | {$ENDIF} 6 | 7 | function ror(x: Cardinal; y: Byte): Cardinal; assembler; 8 | asm 9 | mov cl,dl 10 | ror eax,cl 11 | end; 12 | 13 | function rol(x: Cardinal; y: Byte): Cardinal; assembler; 14 | asm 15 | mov cl,dl 16 | rol eax,cl 17 | end; 18 | 19 | function bswap(x: Cardinal): Cardinal; assembler; 20 | asm 21 | bswap eax 22 | end; 23 | 24 | function swap64(x: int64): int64; assembler; 25 | asm 26 | mov edx,dword ptr[x] 27 | mov eax,dword ptr[x+4] 28 | bswap edx 29 | bswap eax 30 | end; 31 | {$ELSE} 32 | function ror(x: Cardinal; y: Byte): Cardinal; 33 | begin 34 | ror:= 35 | (x shr y) + 36 | (x shl (32-y)); 37 | end; 38 | 39 | function rol(x: Cardinal; y: Byte): Cardinal; 40 | begin 41 | rol:= 42 | (x shl y) + 43 | (x shr (32-y)); 44 | end; 45 | 46 | function bswap(x: Cardinal): Cardinal; 47 | begin 48 | bswap:= 49 | ((x and $000000FF) shl 24) + 50 | ((x and $0000FF00) shl 8) + 51 | ((x and $00FF0000) shr 8) + 52 | ((x and $FF000000) shr 24); 53 | end; 54 | 55 | function swap64(x: uint64): uint64; 56 | begin 57 | swap64:= 58 | ((x and $00000000000000FF) shl 56) + 59 | ((x and $000000000000FF00) shl 40) + 60 | ((x and $0000000000FF0000) shl 24) + 61 | ((x and $00000000FF000000) shl 8) + 62 | ((x and $000000FF00000000) shr 8) + 63 | ((x and $0000FF0000000000) shr 24) + 64 | ((x and $00FF000000000000) shr 40) + 65 | ((x and $FF00000000000000) shr 56); 66 | end; 67 | {$ENDIF} -------------------------------------------------------------------------------- /datamodule.dfm: -------------------------------------------------------------------------------- 1 | object dm: Tdm 2 | OldCreateOrder = False 3 | Height = 183 4 | Width = 265 5 | object dbconnection: TFDConnection 6 | Params.Strings = ( 7 | 'ConnectionDef=btcblockchaindb') 8 | LoginPrompt = False 9 | Left = 57 10 | Top = 20 11 | end 12 | object aQuery: TFDQuery 13 | Connection = dbconnection 14 | SQL.Strings = ( 15 | '') 16 | Left = 144 17 | Top = 88 18 | end 19 | object FDPhysPgDriverLink1: TFDPhysPgDriverLink 20 | Left = 56 21 | Top = 111 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /datamodule.pas: -------------------------------------------------------------------------------- 1 | unit datamodule; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, 7 | FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, 8 | FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.PG, 9 | FireDAC.Phys.PGDef, FireDAC.VCLUI.Wait, Data.DB, FireDAC.Comp.Client, 10 | BlocksUnit, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, 11 | FireDAC.Comp.DataSet; 12 | 13 | type 14 | Tdm = class(TDataModule) 15 | dbconnection: TFDConnection; 16 | aQuery: TFDQuery; 17 | FDPhysPgDriverLink1: TFDPhysPgDriverLink; 18 | private 19 | { Private declarations } 20 | public 21 | { Public declarations } 22 | function InsertBlock(aBlock: TBlockRecord): boolean; 23 | end; 24 | 25 | var 26 | dm: Tdm; 27 | 28 | implementation 29 | 30 | uses 31 | System.DateUtils, 32 | SeSHA256; 33 | 34 | {%CLASSGROUP 'Vcl.Controls.TControl'} 35 | {$R *.dfm} 36 | { Tdm } 37 | 38 | function Tdm.InsertBlock(aBlock: TBlockRecord): boolean; 39 | var 40 | aPreviousBlock, aMerkleRoot, aNextBlock: string; 41 | aTime: TDateTime; 42 | begin 43 | aQuery.SQL.Clear; 44 | 45 | aPreviousBlock := T32ToString(aBlock.header.aPreviousBlockHash); 46 | { 47 | if aPreviousBlock = 0 then 48 | begin 49 | aPreviousId := 0; 50 | end 51 | else 52 | begin 53 | 54 | end; } 55 | 56 | aMerkleRoot := T32ToString(aBlock.header.aMerkleRoot); 57 | aTime := UnixToDateTime(aBlock.header.time); 58 | 59 | aQuery.SQL.Add 60 | (format('insert into blocks (hash,amerkleroot,time) values (''%s'',''%s'',''%s'')', 61 | [aBlock.hash, aMerkleRoot, DateTimeToStr(aTime)])); 62 | 63 | aQuery.ExecSQL; 64 | aQuery.Close; 65 | end; 66 | 67 | end. 68 | -------------------------------------------------------------------------------- /sample-config.ini: -------------------------------------------------------------------------------- 1 | [File] 2 | BlockFilePath= 3 | 4 | [Postgresql] 5 | host= 6 | db= 7 | port= 8 | user= 9 | password= 10 | --------------------------------------------------------------------------------