diff --git a/README.md b/README.md index 70bfb9a3..c193f8d3 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,17 @@ -datacoin-hp -=========== +Datacoin High Performance Version 14 +==================================== -High-performance version of datacoin (primecoin-hp fork). +This is fork of datacoin-hp by foo1inge (https://github.com/foo1inge/datacoin-hp). +The latest release by the original dev was hp11. +This is the hp14 release (encompassing changes from primecoin-0.1.2-hp14). +Datacoin is a fork of Primecoin (http://primecoin.org) +If you like it, donate: -Primecoin High Performance Version -================================== +DTC: DSSHsB1R8mrZd1ujhxcPqQaqAu2cNZsCNn -This is the high performance version of Sunny King's Primecoin tree. +XPM: AL1nofFch3VPvJYGNYSbKwcW9xhrtyTAAh -Features: - * Use GMP for bignum calculations in the mining threads - * Replaced some bignum calculations with 64-bit arithmetic inside the sieve - * Reduced the amount of memory allocations - * L1 and L2 cache optimizations - * Process only 10% of base primes when weaving the sieve - * Configurable sieve size +g1g0 -Donations are welcome if you want to support my work. - -BTC: 1EaHwHBWeoJtSM2jEdx9Su1NcKvdXbsqxX -LTC: LPD1zDChmqcqKGHFHuLX2JWMMEC5jD5J4j -XPM: AJHjbkVzHhHugd5bpKDtddVDfhtEB8jQZ4 - -Primecoin integration/staging tree -================================== - -http://primecoin.org - -Copyright (c) 2013 Primecoin Developers - -Copyright (c) 2009-2013 Bitcoin Developers - -Copyright (c) 2011-2013 PPCoin Developers - -What is Primecoin? ------------------- - -Primecoin is an experimental cryptocurrency that introduces the first -scientific computing proof-of-work to cryptocurrency technology. Primecoin's -proof-of-work is an innovative design based on searching for prime number -chains, providing potential scientific value in addition to minting and -security for the network. Similar to Bitcoin, Primecoin enables instant payments -to anyone, anywhere in the world. It also uses peer-to-peer technology to -operate with no central authority: managing transactions and issuing money are -carried out collectively by the network. Primecoin is also the name of the open -source software which enables the use of this currency. - -For more information, as well as an immediately useable, binary version of -the Primecoin client sofware, see http://primecoin.org. - -License -------- - -Primecoin is released under conditional MIT license. See COPYING` for more -information. - -Development process -------------------- - -Developers work in their own trees, then submit pull requests when they think -their feature or bug fix is ready. - -If it is a simple/trivial/non-controversial change, then one of the Bitcoin -development team members simply pulls it. - -If it is a *more complicated or potentially controversial* change, then the patch -submitter will be asked to start a discussion (if they haven't already) on the -ppcoin/primecoin forum (http://ppcointalk.org). - -The patch will be accepted if there is broad consensus that it is a good thing. -Developers should expect to rework and resubmit patches if the code doesn't -match the project's coding conventions (see `doc/coding.txt`) or are -controversial. - -The `master` branch is regularly built and tested, but is not guaranteed to be -completely stable. [Tags](https://github.com/primecoin/primecoin/tags) are -created regularly to indicate new official, stable release versions of -Primecoin. - -Testing -------- - -Testing and code review is the bottleneck for development; we get more pull -requests than we can review and test. Please be patient and help out, and -remember this is a security-critical project where any mistake might cost people -lots of money. - -### Automated Testing - -Developers are strongly encouraged to write unit tests for new code, and to -submit new unit tests for old code. - -Unit tests for the core code are in `src/test/`. To compile and run them: - - cd src; make -f makefile.unix test - -Unit tests for the GUI code are in `src/qt/test/`. To compile and run them: - - qmake BITCOIN_QT_TEST=1 -o Makefile.test bitcoin-qt.pro - make -f Makefile.test - ./bitcoin-qt_test - -### Manual Quality Assurance (QA) Testing - -Large changes should have a test plan, and should be tested by somebody other -than the developer who wrote the code. - -See https://github.com/bitcoin/QA/ for how to create a test plan. -======= -datacoin-hp -=========== - -High-performance version of datacoin (primecoin-hp fork) +P.S. Please note, that the default donation behaviour has changed (according to changes in Primecoin). Now it is set to 1 percent of mined coins which is sent to the DTC address above. If you don't like it, change it in the sources or specify explicitly during the normal datacoind server start with (not documented in the help) options: -donationpercentage - default 1, and -donationaddress. diff --git a/contrib/gitian-downloader/linux-download-config b/contrib/gitian-downloader/linux-download-config index aef614d0..8340a5dd 100644 --- a/contrib/gitian-downloader/linux-download-config +++ b/contrib/gitian-downloader/linux-download-config @@ -35,4 +35,8 @@ signers: weight: 40 name: "Wladimir J. van der Laan" key: laanwj + AEC1884398647C47413C1C3FB1179EB7347DC10D: + weight: 40 + name: "Warren Togami" + key: wtogami minimum_weight: 120 diff --git a/contrib/gitian-downloader/win32-download-config b/contrib/gitian-downloader/win32-download-config index 0f7032e6..49d52851 100644 --- a/contrib/gitian-downloader/win32-download-config +++ b/contrib/gitian-downloader/win32-download-config @@ -35,4 +35,8 @@ signers: weight: 40 name: "Wladimir J. van der Laan" key: laanwj + AEC1884398647C47413C1C3FB1179EB7347DC10D: + weight: 40 + name: "Warren Togami" + key: wtogami minimum_weight: 120 diff --git a/contrib/gitian-downloader/wtogami-key.pgp b/contrib/gitian-downloader/wtogami-key.pgp new file mode 100644 index 00000000..e0f6c4c5 --- /dev/null +++ b/contrib/gitian-downloader/wtogami-key.pgp @@ -0,0 +1,131 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.13 (GNU/Linux) + +mQQNBFHOzpUBIADYwJ1vC5npnYCthOtiSna/siS6tdol0OXc82QRgK4Q2YeFCkpN +Fw/T5YK34BLVGWDHPoafG2+r1nXIuMZnJIiGw6QVOL2sP9f7PrMmzck5KJPHD14Y +GRd9BPkhmt3dXzOCjhig7jI6hKEYayfJNUNs9nlZEvl4QWIBMmk+IyqQz3f1HMfl +/GkFDShBYF8Ny7Ktlx7AaXymajm4DCrTkbj5V2ZDqJgyQM549EoPSwXBQYrEjye3 +g2viC8rUFRFWFjdnx7jFEb1uhx71YGuqiLxKihUW9pbSNK2cLweFazHSVmh+B/pz +fxHfUn+ijLSIAnprTmc/rq89un/iiPt0O/mspcCZ6hE5pFIyX+SC+9PrGz+bFSmw +PkMOZzG489G8k4t/uZsit6helkl0emg6JiXLTmS/oTuT7B9Z9/MeEhOXFcxUb0fr +2aZkEmH5d1oxSBis3D5nylmNJXOUSCpJAZ8E5Sr/5FbF9IPR+NSzosVacqCx5Dxj +vJ7HpZKn6pJfmwrghVXQv04NRTcxbHNmwd98cofBtWX8yBO8M2M+jZrU+BVDUbb/ +A1oAyIbUUswBP768Oh11bELhCly774VwBqTojm2yodLGSyysx4zoa6qL7myfor0m +a+K29y8WH9XGmKGMdUOg+q9z+ODky9aToGvEo2eVhKIlJsk0aFAGy/8awy6qRIIj +UqLMq6XoFcYlE7SmnFUDDDPlBK/NkFFqySpFhKNRyt69Ea9kYXOxDnf/EnBwHn8m +PiFQpeZqgnmhyj8Nk1SSQBgUi07NyXdQ/WIYpWmqqqfHRVQgSE9C1920T1zg/E97 +n5yYjI/gQQwq9wikkJmog6Ny7MSiwIU4LYV0pTUdI4//EJMId2FH8YEUfvG5ds+F +H/o/D4CAJ86KjspizfH8jEjhn0Rm/OtrxLz1rwA1gtF//P3TYNWw5qruL4stP3Rx +9Gve8Bm7oCBU73UT2ZJomEsWE3oqXinLRl3YCsjGDg/d3ySD6i0/BBROLIeXkh3M +M1CNCqREDGLA0vxQi1o7Zi7ZA4gWPSzvi/8KtSzY1iAQODxWUmOICRP7KQODWJmt +roTqhKgZ39wlR6eqkO8ZfAvRYsjvkL+EZFbbKbHxVJLhKchd2qHS+/Q3ov4SFzWY +/cE0ChOPDM587Jkps2bynKQAzQ6810FXmJc0ztrPeD3PEbuyY4KNJV8HGViRDJXi +wvs8eqfvTDGDPl4aLYVCKO9VqZ2OJvqhRhh71LQ2xRrX1LGnYLnUGCMuEQYKvMcI +TSssM/VAfeWAPJDklD0lVNJ7d9Z5ugvJHFc01SaaB47Aod2SPWp5DeiY4A8dcy2w +7f4Wx6FcdP1RXqaRZKCapBooN04vsvGllCshABEBAAG0KFdhcnJlbiBUb2dhbWkg +KDIwMTMpIDx3dG9nYW1pQGdtYWlsLmNvbT6JBDgEEwECACIFAlHOzpUCGwMGCwkI +BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJELEXnrc0fcENY4Ef/23L9iC/39ekJ8Is +1IZdCoDD7/DgVaZqydDcy/ha9uaDFY4MQ0h9RZYo1axVBth/Yxzh1XnvitW8HFKn +DXn5wJI++KWpdLMUsTrc2iWsjAGgicmN5bkQvfTnRwn2pF17EUUEhZ8YyE3qMSVD +rDBECLAswT4Oiq9r9yw3VCFsRaxz5bhk9AAzWjam4H7mAfaEAOUvuX221v+KGSDM +UsGAAe+GjMPL8KnGgEbISlSUF1Ubcw3EChcqjf3BID2gMLkAnGAoxlCZSYievytg +71mcHyIf9yF861QrGcrCh6/objtRdt4IDUVwo9wapunRmYCdZux4ApD0Hit8nAsm +QtxftSK6FWBTOCIRoOQTjwE8qj9GYTIbUFppX66Dzh00td5NKkWz0PVze7YSk2hC +KCVBYyUYHgkQYVlYLZw7dBrXSXv7ph95vc93RDS031cU7tPOrthqnMmhtg1WAwzH +xc2v3az9Gsw1RyxBAOVpkB0AFODiEiVg46xqmxaBPXfQOg/buZA2l4gK4U/pVUZH +72lle2CbBw6FoSx40Y3GYZWB2uEdXBTNLlhX7q2Jvo8WdeTxEv5ACZsjI7K/wrzt +nmvCHefOmVf4tefkXy1MyEvBt2+Ek9bHmHDL1BSk/JdJzJtam2uaP5pGum/PwIUW +KBatmHKZUKwgOIml9btB413C4zSK3GQmC5Y/+TxYybACIdxTDqPSczVZ5Q+jSywX +shdOoLXDRyrYhT2sHjZ1W29B8ebokqwousF77EA94sqfQvDDnmFpvfq9+m0WYtOh +PFF/yxOtlbPJYX7mnC8+dUgobSA4AR5Yrclt+levgivIyNuBwzevHRDMreMZKl2J +uiOT8tkuu66fAwEltIowjjV7TBRfij4QLXl/zfFo8jKU8efL3xluXoRn7g+E5FZ3 +19KTF/DWMcttfeTUYVnv0QTnstb1RGnVj7w8JMy90mKdMQFpl7IzHd2n6LrhEw1V +1AaPF7EcQBOlvsvlZdIFQrFyhKozKoGi3wRrl/bNdebxjIjPzfN9GgbiufFjz2d7 +DMR9GFXfUMVxLncaqBBy1X7MV17ZF7K4uw6DET4fRoecb4N5mJVUxvYq4iZApnNP +npgGdmlcyPD6o3ynx/vkw78m13Gfgw8i2OaUY7xBdOyNVEvkJZBLaC2hw+TKLaZa +v0RExtAO0i0QO4Y1eo78Pl9jOpz0wkJ4KG0270l1Jza4IyaIhYRDWagWOfOp/cXU +cvKKiuJhLOsX1Bapz+O2Aor9+EwWRdPd3BzE2ABdmKHPwrKobNp75wrCpQ5mZifn +DSTJRMPQQJV3wGfB2sP0NE47U8w5CCmVK8gEuqYr6wBl/CCq5tjiRc63VM+to5V4 +tVNTCJWIRgQQEQIABgUCUc7PqwAKCRBr3f6OVKKs8cYAAKCFCLJ5wc+iAVCFRevh +xTcJct0fiQCePHpY37CIeP8s9BH8GqCDftUqh8SIRgQQEQIABgUCUc7YwAAKCRDd +f+mrhdawLOVxAJ9Tjud26LtbM2mWcPj2eT7dhqgZrQCdGyMwMMVzp40lsCK44PrV ++mpFO7KJAhwEEAECAAYFAlHO0BkACgkQw35HI5aSdvXfLw//c2zZxXg4bI2W7gkB +ZQJIOWnmPZfhrXQNeFuetyGoWTm4ZWxW362AdDGiQSGNNkXqeBPOitKOkRyZP/Z3 +h1vwkLkwdFZyWXK00BzYBKfjThWV1BAnArQLewSiLlE7qSnsPEY6FW0PNv711cbL +lXSUP1/lW25Nx7L76GAF6sHreoIdglE8YH5y310JuFnqPa0uaJG+qDo8Mb+WkyLy +Q2A3Atws1tIB9vHsq2FCt9ACyAEA3AqtHR4uMFmIWpUYy77fJAZdzLZTWf0X5XYw +XILNPOl/I0iZrq3LYQAvJfIwjWAC/lm6uTLlvkIJHKyhcIT+RocjMV7bY9ezrC5i +Cag3gaOZ7USMt0h59KdmBaHHNa32n3PSHg9XWljqoWMRjuaRdcA7ofK0BHDJbHWE +cldKXC09laWOXbyNmJsfug/23vNE7fS/cAKSIgEWszEwHJCahB2i/HqOQF0DUGpq +3s5oIXs2xIuN0yT6yIIiQnTU/FkWDDu4D1OZNrDW6QG3cde0PRak/0fr4Kv4iB3E +CAzlsRBlWKNu/eE4QBx6cbvLqjriijhGAF+8Y1zvRKNKPr96hSsETfVytuKDTp6F +u7PAarrSATGXI92Hy3ThAZla0VOYUyeWPktqUMDNq90tIBZbwKpOMMqvJmZfgdOU +4ldDq1f5+2WhAt1aTL1GJVCuYcCJAhwEEAECAAYFAlHO3MQACgkQnSOpPExjO3Gi +jxAAsD+luooqqoz3A28ZxwfCDV+ovazQ4Bw6hVU0zKKZIz/2H4jwmLtLSHtucCRM +xRksZmnqf1p2nn+BKBXDInx9vI9HziMu7fWkzhuovAIf9+X/l6EYV1kQx0bIM1qU +BxXWPgGdrgSZZHl9Qff/BOBnrI8NJmVBDzOh3BSs0BrSR7aFbkSNbjk/JcP0JEyk +j6wDKQsop/Ca5AboLL0uQPgTvhxCu4VROKjhu7o3s7G3xlxTpimwYklDQuYFaGKj +ZNIGFq2orfIMBnj7ZEQVXzhWltlHcgPVP5TDfgd4pVUbyUB6ras7odJWWIHnUFmj +1l5bGidIwRXGFusE4iR8pR528LG2KxNDNQYipsKRY9m+wH+N7gbSgK8DxmocvieV +vcILFS5VrPLbEO2oC13NMljmvua3ovDB0CEh9rybaH+/oA+VDS2L3pkgATTju+Vx +6+mVdlvnrA4mJ5BoLHzrleKybS4ZkbtVBh1KOYmo95NgVifRvpVPB6hKzwqcjYFV +fVYBxTryTBRyd9MLsqpPKnGLBENTFvKDxRCK3iioNyVhXdS0z/UyF1C2hwNTpnjY +pGCu+Es3SILJg2TvQcwLM0OoYBA1bcONm2XbkTrdCpTOtQcSewQSkijREunx14iu +pvNSWeNmbjQU7gNYhvwcBgh90tWgNCfqTtSa5xSe46tmv0SJAhwEEAECAAYFAlHQ +1hgACgkQZwn/QC8Dr2hT/g/+OFUYPXfWo0+ILdxyTGP/v2mSw/X3dBCEYUqefWxD +umcwnksey+thEGFBlxbwpyOfAoTzZLUupaG6BacVgRUvv8bTne4v2H1d22aBXyjC +HMtQPhupn/giamu8q8hCPFrDp6inIAeFuz1GmQaH6xWO5eYBuYXQtxlvZLWBsuMT +74en4e3vjczxGmJu/nvM9ugcYsexA/zcN6SRGr7t2pV4ZElPzPBRyAzhYqhP1YlB +Rydz60OjgcWYEoJKWhJOfmFJ3ZoNGAz4TGoBkDIq4olCF0/cxqrtHN+ZnEOLwiZ7 +4ZX90avcjEFtM+Wb5dBHNpni4ISoHcVI1X0ye6tuAOOt7RywbET/0oIW5iSNMgJ0 +X4XYgOIQ2+a8yjGBjo9I57k0vp1mL6Ji/eaa0dlppcCGnzvSHss+O0qO212pg5Yk +GGfjX1y1ZeSP3ca9C2XyOGIVw2d2Iu7OyqAv/N81xt6ZgG3qixQC0nmgOmn7Kh2B +20W12KpLxKS8RQdHawGau3MBGKeqbfK6/eAzm22yD4/yJAoW4hKgm84z3FbKUN8w +ulYMK9hS2c4egpoDAOJ/QZLLXFWiyi7/sHZz69G2AweWCjOJh28Otg0cUHoLo7jw +oO/L0rCsOQMbUuIumYXBPHNnDwv1xfv2lT8tVzf6GksFJBAw0DybxOMTaOg45Lhz +jGS5BA0EUc7OlQEgAN6t+BV705uoCsdHtQBq/HKGGD5tBiOzy7Wd4nF/c6EWzET4 +QUnmw6bDnqjxrk9MWniPDf1O9MvuB4qIY6g9kEjZ+VSQpWUZpZ5bMXCNHrfh9J2Q +6oLWqDmpeZv2OI0O9wxT62QaFei2qBtimSnBudLSCnvmU3S0h1PflmJsbj+tVcko +w2yOh2bjH1jkVAODHvEbxqyD6fiZhbfUVbPC49SBmXv8Gv0UywNSkP+iqJdwZAb0 +XtjRx4WjZCkTwJAnbM4CJ63+5Hd83BtWZAZbGAh76XY/cSkDirXtXC+2LNUmP5W2 +QY+ur5Bvz8LHaqJMXLAtePdkv5kpd+jXBrZieXUtqovxZaQTinl7C3L2TZd/ivxD +F3Rko9BFDuXXcdZrxBY5b3146IvSPp1y0WmHRxhAPb+RuiHQMt8K92nOhPyvtWXB +mWz0GnW9L6+CW4LKSPRSnE057hyxYNP/DcDd+fWFH+MmhU9noqHfJXSaLVzdI5PI +L8N44AndPIojnlxrxRs7Ik/nW6cTV9H3agg+24yyTdFkACbfIS6wWXOHeHuBzmO6 +VI7pXOZJ9vZT7zI7M/hVci0R3putsGqgRfByRWWQ2DNeyrwUHexZNR/NYz1uhvA6 +dBfKcuAwqxbdSrW/BxJ+iJWdkgYGCV67VLlO6S9sO33HgOanpPr5R9V1KsFVh4dN +j6BjZ4ALE5FPNW+iONnuXvtZbN2cBlBzMDeFC9oZoYCs1Pkmk8xUY2sAXPUt1R0G +D/miIb7ig1N52j9P6vv6fPs1ghmc/hGkhaXyjS54B5T33V6M9g+yba9mIgi8ZxZa +G+4rlFFKA4HS7wYYRJoqMvnc/qBYvoWLaPu3Xq6AXrJyuAaN+e3L8++cWbYHBXF9 +qt+Q2RFL0FNiYUQuwkiaerysnm1a0H7ZtJ4zjl4ZgA1Ej7QcylTIbgFW3L7FnyMH +/5weLLN2wdjAtzjhRPYJLbV6V/gFbbpCpr+caDUaxSNizQuhhzVI5UrJegaHCCrx +DCiwWRFYzN5pqhtgzcaImK76DmPIk+Yrsum5KJZQeGfzKxvF0YnwxU0bxFzcDZJD +X2oCJn828Aw2j0nIlVlrrao0JMkvTBeZehO/11U68M2vKGEqrsQOb/BTXyLCeZwn +UGow1WvYfRxEZTrhhiYw94EH06gbqmKG1xsuV4LDI5z63/6ACcQW3orMbMymJCky +4HiNVZ7SNeGoYe380CJCwv6GN1opKTAWp84cr2KzhAzONGqNWNpUhznAXlI+GzCc +D2H330L1atMqZHjgpEfrkowvJ7WBM5KFKDfylaTKhYvfZcTOZs5OmRZSW3U54wRD +RMP0d2+k3vRililNhHIErHbjhYFc6zubVbBhvUMAEQEAAYkEHwQYAQIACQUCUc7O +lQIbDAAKCRCxF563NH3BDSX2IACugAdZqX+o/+pTkSrj+NEAcP0ZMci8w5nm/yOP +VlGyY6PXGuQKcBtvz3LWtIDdddMc/bD/zmZPwSzTx1MMOWc+gjR0azXe2RrdMHYk +8pb4X4Op2Nkasoc/8hNsRKaU24WUAQMqrRREIVBEOuHGl1A52Lj+aFB04rRHrkMl +AqjB5bwArPorIBdM417EEl4hjEZ9BpQxbUgBhTgGTZuc1u9PsKz1YvQ79YJIRmSH +n72Zaf35zY55eOQeoVBzGmFPq+/UFqtRNWA7jmRhHvMz/yR33B/RSxyTJuPb79zi +2mIZOrViG3X/UNL4qtOc1cKXQBi+FjHAMlGrCc+D5lnyOhEvqoEuvQic7V6C8Pvk +9q+jngn2Gs4pdJO8FOnwaC5xp/ZNE0v7x/KtAHyBA6iKcaepgoRQPSt1ONiHyfh1 +iGgJn+Y6IHx4YDYKEY0UIzHhCfWUl8XZWcf4wLGEbGztkRbkCFqrsja5IeaO7umB +i6C4f95uSGjV7SiIMJOE8xo/m2g4VCnnmk7U996JwtBMKREMMqa3ABK4trfBL3Kq +P6I6ZTlA/C5svkVUVwWOMZau9kLDsxv8keGrFteZtfYa1KPAROFwNuBU82UW0KtX +QQbZoBKt1o3LhqEu+hXU3iKocYWSbBThH8u6vPNgSnW2Qcv3gcUU3jGmYeHrGiUO +SuEWxwlKUxCxBNfmz1FGswlwve1LsS3RTz/XB/L6Ubhq5L7FevrXz8152kuMqnpy +m93sXkL1eJVo07hH+otcRnMzy4vUar9z/N12t3hfTffx29PBKUCc2PKPVpLfJX2i +hieHk23fhLnptjc3lm9S+bHO3rqEWHqgNgNp9bpuwiLRsIy6qTtmC8jxXkGXvQrS ++2Hv6+jRfDcqEAK3vqi1XL7Td81KRjnheBtsKpjS2PFatK3uTo6v1oRWJCdRCxg1 +HT6a9KvZ+DNKcxlQISKAOLX72qpziaDl4CpBdQy4Zg2pr9oYkLdlfkaDK/OH4J3M +wJiVf/uNPPd+yy6xZXK0SPZHf+mf5Yt+Sim93hIbdS9AMdvHKB5n3DR27H+/okPj +w3J9z85hxgP5KspizQR6t77AWddPRy/l3BBZeb+HiaeKGBJeSNWXpkPXHkdjLW8U +QStzFR8r15FWJTmamIknjJ3XNbytMCpu8cj2ZVZdyjPcHEBL3WbNYYtauSuYmyUO +yXBaecM/KoTdvHiERU/mMuf7f1ftftCHehZoNaP+BeIbIud9IHIdrSQBCW+RC1Y1 +8opDLMtnIOX3OnyCN38ELYcuNLMJxBqnQgi7MVDVcT1+BN/+lFQtG44+rPUkK+T1 +Jk1/tIJqcyc1BfY6uFHFXWWnqQnjl0XpZo+/bMDxTVy8yND2 +=icdI +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/homebrew/makefile.osx.patch b/contrib/homebrew/makefile.osx.patch index 340de0ef..287db2fd 100644 --- a/contrib/homebrew/makefile.osx.patch +++ b/contrib/homebrew/makefile.osx.patch @@ -1,5 +1,5 @@ diff --git a/src/makefile.osx b/src/makefile.osx -index 8b7c559..8a0560c 100644 +index bef0ef3..07ef8d3 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -7,17 +7,21 @@ @@ -28,7 +28,7 @@ index 8b7c559..8a0560c 100644 USE_UPNP:=1 USE_IPV6:=1 -@@ -31,13 +35,13 @@ ifdef STATIC +@@ -31,14 +35,14 @@ ifdef STATIC TESTLIBS += \ $(DEPSDIR)/lib/libboost_unit_test_framework-mt.a LIBS += \ @@ -38,6 +38,7 @@ index 8b7c559..8a0560c 100644 $(DEPSDIR)/lib/libboost_filesystem-mt.a \ $(DEPSDIR)/lib/libboost_program_options-mt.a \ $(DEPSDIR)/lib/libboost_thread-mt.a \ + $(DEPSDIR)/lib/libboost_chrono-mt.a \ - $(DEPSDIR)/lib/libssl.a \ - $(DEPSDIR)/lib/libcrypto.a \ + $(OPENSSLDIR)/lib/libssl.a \ diff --git a/contrib/macdeploy/fancy.plist b/contrib/macdeploy/fancy.plist index e73b9b69..f8f29f97 100644 --- a/contrib/macdeploy/fancy.plist +++ b/contrib/macdeploy/fancy.plist @@ -22,7 +22,7 @@ 370 156 - Bitcoin-Qt.app + Datacoin-HP-Qt.app 128 156 diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 11140d3b..d352b33a 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -763,7 +763,7 @@ if config.dmg is not None: items_positions.append(itemscript.substitute(params)) params = { - "disk" : "Bitcoin-Qt", + "disk" : "Datacoin-HP-Qt", "window_bounds" : "300,300,800,620", "icon_size" : "96", "background_commands" : "", diff --git a/contrib/verifysfbinaries/verify.sh b/contrib/verifysfbinaries/verify.sh index d449211c..cd9d2d0d 100755 --- a/contrib/verifysfbinaries/verify.sh +++ b/contrib/verifysfbinaries/verify.sh @@ -18,7 +18,7 @@ WORKINGDIR="/tmp/bitcoin" TMPFILE="hashes.tmp" #this URL is used if a version number is not specified as an argument to the script -SIGNATUREFILE="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.8.3/SHA256SUMS.asc" +SIGNATUREFILE="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.8.6/SHA256SUMS.asc" SIGNATUREFILENAME="SHA256SUMS.asc" RCSUBDIR="test/" diff --git a/datacoin-qt-win64.pro b/datacoin-qt-win64.pro deleted file mode 100644 index e65414e3..00000000 --- a/datacoin-qt-win64.pro +++ /dev/null @@ -1,430 +0,0 @@ -TEMPLATE = app -TARGET = datacoin-qt -macx:TARGET = "Datacoin-Qt" -VERSION = 0.8.3 -INCLUDEPATH += src src/json src/qt -QT += network -DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE -CONFIG += no_include_pwd -CONFIG += thread - -# win32: Some defines needed for clean compile with mingw64 -win32:DEFINES += FD_SETSIZE=1024 BOOST_USE_WINDOWS_H WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x501 - -# for boost 1.37, add -mt to the boost libraries -# use: qmake BOOST_LIB_SUFFIX=-mt -# for boost thread win32 with _win32 sufix -# use: BOOST_THREAD_LIB_SUFFIX=_win32-... -# or when linking against a specific BerkelyDB version: BDB_LIB_SUFFIX=-4.8 - -# Dependency library locations can be customized with: -# BOOST_INCLUDE_PATH, BOOST_LIB_PATH, BDB_INCLUDE_PATH, -# BDB_LIB_PATH, OPENSSL_INCLUDE_PATH and OPENSSL_LIB_PATH respectively - -OBJECTS_DIR = build -MOC_DIR = build -UI_DIR = build - -# use: qmake "RELEASE=1" -contains(RELEASE, 1) { - # Mac: compile for maximum compatibility (10.5, 32-bit) - macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk - macx:QMAKE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk - macx:QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk - - !win32:!macx { - # Linux: static link and extra security (see: https://wiki.debian.org/Hardening) - LIBS += -Wl,-Bstatic -Wl,-z,relro -Wl,-z,now - - # Linux: Enable bundling libgmp.so with the binary - LIBS += -Wl,-rpath,\\\$$ORIGIN - } -} - -!win32 { - # for extra security against potential buffer overflows: enable GCCs Stack Smashing Protection - QMAKE_CXXFLAGS *= -fstack-protector-all - QMAKE_LFLAGS *= -fstack-protector-all - # Exclude on Windows cross compile with MinGW 4.2.x, as it will result in a non-working executable! - # This can be enabled for Windows, when we switch to MinGW >= 4.4.x. -} -# for extra security (see: https://wiki.debian.org/Hardening): this flag is GCC compiler-specific -QMAKE_CXXFLAGS *= -D_FORTIFY_SOURCE=2 -# for extra security on Windows: enable ASLR and DEP via GCC linker flags -win32:QMAKE_LFLAGS *= -Wl,--dynamicbase -Wl,--nxcompat - -# use: qmake "USE_QRCODE=1" -# libqrencode (http://fukuchi.org/works/qrencode/index.en.html) must be installed for support -contains(USE_QRCODE, 1) { - message(Building with QRCode support) - DEFINES += USE_QRCODE - LIBS += -lqrencode -} - -# use: qmake "USE_UPNP=1" ( enabled by default; default) -# or: qmake "USE_UPNP=0" (disabled by default) -# or: qmake "USE_UPNP=-" (not supported) -# miniupnpc (http://miniupnp.free.fr/files/) must be installed for support -contains(USE_UPNP, -) { - message(Building without UPNP support) -} else { - message(Building with UPNP support) - count(USE_UPNP, 0) { - USE_UPNP=1 - } - DEFINES += USE_UPNP=$$USE_UPNP STATICLIB - INCLUDEPATH += $$MINIUPNPC_INCLUDE_PATH - LIBS += $$join(MINIUPNPC_LIB_PATH,,-L,) -lminiupnpc - win32:LIBS += -liphlpapi -} - -# use: qmake "USE_DBUS=1" -contains(USE_DBUS, 1) { - message(Building with DBUS (Freedesktop notifications) support) - DEFINES += USE_DBUS - QT += dbus -} - -# use: qmake "USE_IPV6=1" ( enabled by default; default) -# or: qmake "USE_IPV6=0" (disabled by default) -# or: qmake "USE_IPV6=-" (not supported) -contains(USE_IPV6, -) { - message(Building without IPv6 support) -} else { - count(USE_IPV6, 0) { - USE_IPV6=1 - } - DEFINES += USE_IPV6=$$USE_IPV6 -} - -contains(BITCOIN_NEED_QT_PLUGINS, 1) { - DEFINES += BITCOIN_NEED_QT_PLUGINS - QTPLUGIN += qcncodecs qjpcodecs qtwcodecs qkrcodecs qtaccessiblewidgets -} - -INCLUDEPATH += src/leveldb/include src/leveldb/helpers -LIBS += $$PWD/src/leveldb/libleveldb.a $$PWD/src/leveldb/libmemenv.a -!win32 { - # we use QMAKE_CXXFLAGS_RELEASE even without RELEASE=1 because we use RELEASE to indicate linking preferences not -O preferences - genleveldb.commands = cd $$PWD/src/leveldb && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) OPT=\"$$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_RELEASE\" libleveldb.a libmemenv.a -} else { - # make an educated guess about what the ranlib command is called - isEmpty(QMAKE_RANLIB) { - QMAKE_RANLIB = $$replace(QMAKE_STRIP, strip, ranlib) - } - LIBS += -lshlwapi - genleveldb.commands = cd $$PWD/src/leveldb && CC=$$QMAKE_CC CXX=$$QMAKE_CXX TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) OPT=\"$$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_RELEASE\" libleveldb.a libmemenv.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libleveldb.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libmemenv.a -} -genleveldb.target = $$PWD/src/leveldb/libleveldb.a -genleveldb.depends = FORCE -PRE_TARGETDEPS += $$PWD/src/leveldb/libleveldb.a -QMAKE_EXTRA_TARGETS += genleveldb -# Gross ugly hack that depends on qmake internals, unfortunately there is no other way to do it. -QMAKE_CLEAN += $$PWD/src/leveldb/libleveldb.a; cd $$PWD/src/leveldb ; $(MAKE) clean - -# regenerate src/build.h -!win32|contains(USE_BUILD_INFO, 1) { - genbuild.depends = FORCE - genbuild.commands = cd $$PWD; /bin/sh share/genbuild.sh $$OUT_PWD/build/build.h - genbuild.target = $$OUT_PWD/build/build.h - PRE_TARGETDEPS += $$OUT_PWD/build/build.h - QMAKE_EXTRA_TARGETS += genbuild - DEFINES += HAVE_BUILD_INFO -} - -QMAKE_CXXFLAGS_WARN_ON = -fdiagnostics-show-option -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wstack-protector - -# Input -DEPENDPATH += src src/json src/qt -HEADERS += src/qt/bitcoingui.h \ - src/qt/transactiontablemodel.h \ - src/qt/addresstablemodel.h \ - src/qt/optionsdialog.h \ - src/qt/sendcoinsdialog.h \ - src/qt/addressbookpage.h \ - src/qt/signverifymessagedialog.h \ - src/qt/aboutdialog.h \ - src/qt/editaddressdialog.h \ - src/qt/bitcoinaddressvalidator.h \ - src/alert.h \ - src/addrman.h \ - src/base58.h \ - src/bignum.h \ - src/checkpoints.h \ - src/compat.h \ - src/sync.h \ - src/util.h \ - src/hash.h \ - src/uint256.h \ - src/serialize.h \ - src/main.h \ - src/net.h \ - src/key.h \ - src/db.h \ - src/walletdb.h \ - src/script.h \ - src/init.h \ - src/bloom.h \ - src/mruset.h \ - src/checkqueue.h \ - src/json/json_spirit_writer_template.h \ - src/json/json_spirit_writer.h \ - src/json/json_spirit_value.h \ - src/json/json_spirit_utils.h \ - src/json/json_spirit_stream_reader.h \ - src/json/json_spirit_reader_template.h \ - src/json/json_spirit_reader.h \ - src/json/json_spirit_error_position.h \ - src/json/json_spirit.h \ - src/qt/clientmodel.h \ - src/qt/guiutil.h \ - src/qt/transactionrecord.h \ - src/qt/guiconstants.h \ - src/qt/optionsmodel.h \ - src/qt/monitoreddatamapper.h \ - src/qt/transactiondesc.h \ - src/qt/transactiondescdialog.h \ - src/qt/bitcoinamountfield.h \ - src/wallet.h \ - src/keystore.h \ - src/qt/transactionfilterproxy.h \ - src/qt/transactionview.h \ - src/qt/walletmodel.h \ - src/qt/walletview.h \ - src/qt/walletstack.h \ - src/qt/walletframe.h \ - src/bitcoinrpc.h \ - src/qt/overviewpage.h \ - src/qt/csvmodelwriter.h \ - src/crypter.h \ - src/qt/sendcoinsentry.h \ - src/qt/qvalidatedlineedit.h \ - src/qt/bitcoinunits.h \ - src/qt/qvaluecombobox.h \ - src/qt/askpassphrasedialog.h \ - src/protocol.h \ - src/qt/notificator.h \ - src/qt/paymentserver.h \ - src/allocators.h \ - src/ui_interface.h \ - src/qt/rpcconsole.h \ - src/version.h \ - src/netbase.h \ - src/clientversion.h \ - src/txdb.h \ - src/leveldb.h \ - src/threadsafety.h \ - src/limitedmap.h \ - src/qt/splashscreen.h - -SOURCES += src/qt/bitcoin.cpp \ - src/qt/bitcoingui.cpp \ - src/qt/transactiontablemodel.cpp \ - src/qt/addresstablemodel.cpp \ - src/qt/optionsdialog.cpp \ - src/qt/sendcoinsdialog.cpp \ - src/qt/addressbookpage.cpp \ - src/qt/signverifymessagedialog.cpp \ - src/qt/aboutdialog.cpp \ - src/qt/editaddressdialog.cpp \ - src/qt/bitcoinaddressvalidator.cpp \ - src/alert.cpp \ - src/version.cpp \ - src/sync.cpp \ - src/util.cpp \ - src/hash.cpp \ - src/netbase.cpp \ - src/key.cpp \ - src/script.cpp \ - src/main.cpp \ - src/init.cpp \ - src/net.cpp \ - src/bloom.cpp \ - src/checkpoints.cpp \ - src/addrman.cpp \ - src/db.cpp \ - src/walletdb.cpp \ - src/qt/clientmodel.cpp \ - src/qt/guiutil.cpp \ - src/qt/transactionrecord.cpp \ - src/qt/optionsmodel.cpp \ - src/qt/monitoreddatamapper.cpp \ - src/qt/transactiondesc.cpp \ - src/qt/transactiondescdialog.cpp \ - src/qt/bitcoinstrings.cpp \ - src/qt/bitcoinamountfield.cpp \ - src/wallet.cpp \ - src/keystore.cpp \ - src/qt/transactionfilterproxy.cpp \ - src/qt/transactionview.cpp \ - src/qt/walletmodel.cpp \ - src/qt/walletview.cpp \ - src/qt/walletstack.cpp \ - src/qt/walletframe.cpp \ - src/bitcoinrpc.cpp \ - src/rpcdump.cpp \ - src/rpcnet.cpp \ - src/rpcmining.cpp \ - src/rpcwallet.cpp \ - src/rpcblockchain.cpp \ - src/rpcrawtransaction.cpp \ - src/qt/overviewpage.cpp \ - src/qt/csvmodelwriter.cpp \ - src/crypter.cpp \ - src/qt/sendcoinsentry.cpp \ - src/qt/qvalidatedlineedit.cpp \ - src/qt/bitcoinunits.cpp \ - src/qt/qvaluecombobox.cpp \ - src/qt/askpassphrasedialog.cpp \ - src/protocol.cpp \ - src/qt/notificator.cpp \ - src/qt/paymentserver.cpp \ - src/qt/rpcconsole.cpp \ - src/noui.cpp \ - src/leveldb.cpp \ - src/txdb.cpp \ - src/qt/splashscreen.cpp \ - src/prime.cpp \ - src/checkpointsync.cpp - -RESOURCES += src/qt/bitcoin.qrc - -FORMS += src/qt/forms/sendcoinsdialog.ui \ - src/qt/forms/addressbookpage.ui \ - src/qt/forms/signverifymessagedialog.ui \ - src/qt/forms/aboutdialog.ui \ - src/qt/forms/editaddressdialog.ui \ - src/qt/forms/transactiondescdialog.ui \ - src/qt/forms/overviewpage.ui \ - src/qt/forms/sendcoinsentry.ui \ - src/qt/forms/askpassphrasedialog.ui \ - src/qt/forms/rpcconsole.ui \ - src/qt/forms/optionsdialog.ui - -contains(USE_QRCODE, 1) { -HEADERS += src/qt/qrcodedialog.h -SOURCES += src/qt/qrcodedialog.cpp -FORMS += src/qt/forms/qrcodedialog.ui -} - -contains(BITCOIN_QT_TEST, 1) { -SOURCES += src/qt/test/test_main.cpp \ - src/qt/test/uritests.cpp -HEADERS += src/qt/test/uritests.h -DEPENDPATH += src/qt/test -QT += testlib -TARGET = bitcoin-qt_test -DEFINES += BITCOIN_QT_TEST - macx: CONFIG -= app_bundle -} - -CODECFORTR = UTF-8 - -# for lrelease/lupdate -# also add new translations to src/qt/bitcoin.qrc under translations/ -TRANSLATIONS = $$files(src/qt/locale/bitcoin_*.ts) - -isEmpty(QMAKE_LRELEASE) { - win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\\lrelease.exe - else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease -} -isEmpty(QM_DIR):QM_DIR = $$PWD/src/qt/locale -# automatically build translations, so they can be included in resource file -TSQM.name = lrelease ${QMAKE_FILE_IN} -TSQM.input = TRANSLATIONS -TSQM.output = $$QM_DIR/${QMAKE_FILE_BASE}.qm -TSQM.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} -TSQM.CONFIG = no_link -QMAKE_EXTRA_COMPILERS += TSQM - -# "Other files" to show in Qt Creator -OTHER_FILES += README.md \ - doc/*.rst \ - doc/*.txt \ - src/qt/res/bitcoin-qt.rc \ - src/test/*.cpp \ - src/test/*.h \ - src/qt/test/*.cpp \ - src/qt/test/*.h - -# platform specific defaults, if not overridden on command line -isEmpty(BOOST_LIB_SUFFIX) { - macx:BOOST_LIB_SUFFIX = -mt - win32:BOOST_LIB_SUFFIX = -mt -} - -isEmpty(BOOST_THREAD_LIB_SUFFIX) { - BOOST_THREAD_LIB_SUFFIX = $$BOOST_LIB_SUFFIX -} - -isEmpty(BDB_LIB_PATH) { - macx:BDB_LIB_PATH = /opt/local/lib/db48 -} - -isEmpty(BDB_LIB_SUFFIX) { - macx:BDB_LIB_SUFFIX = -4.8 -} - -isEmpty(BDB_INCLUDE_PATH) { - macx:BDB_INCLUDE_PATH = /opt/local/include/db48 -} - -isEmpty(BOOST_LIB_PATH) { - macx:BOOST_LIB_PATH = /opt/local/lib -} - -isEmpty(BOOST_INCLUDE_PATH) { - macx:BOOST_INCLUDE_PATH = /opt/local/include -} - -win32:DEFINES += WIN32 -win32:RC_FILE = src/qt/res/bitcoin-qt.rc - -win32:!contains(MINGW_THREAD_BUGFIX, 0) { - # At least qmake's win32-g++-cross profile is missing the -lmingwthrd - # thread-safety flag. GCC has -mthreads to enable this, but it doesn't - # work with static linking. -lmingwthrd must come BEFORE -lmingw, so - # it is prepended to QMAKE_LIBS_QT_ENTRY. - # It can be turned off with MINGW_THREAD_BUGFIX=0, just in case it causes - # any problems on some untested qmake profile now or in the future. - DEFINES += _MT - QMAKE_LIBS_QT_ENTRY = -lmingwthrd $$QMAKE_LIBS_QT_ENTRY -} - -!win32:!macx { - DEFINES += LINUX - LIBS += -lrt - # _FILE_OFFSET_BITS=64 lets 32-bit fopen transparently support large files. - DEFINES += _FILE_OFFSET_BITS=64 -} - -macx:HEADERS += src/qt/macdockiconhandler.h -macx:OBJECTIVE_SOURCES += src/qt/macdockiconhandler.mm -macx:LIBS += -framework Foundation -framework ApplicationServices -framework AppKit -macx:DEFINES += MAC_OSX MSG_NOSIGNAL=0 -macx:ICON = src/qt/res/icons/bitcoin.icns -macx:QMAKE_CFLAGS_THREAD += -pthread -macx:QMAKE_LFLAGS_THREAD += -pthread -macx:QMAKE_CXXFLAGS_THREAD += -pthread -macx:QMAKE_INFO_PLIST = share/qt/Info.plist - -# Set libraries and includes at end, to use platform-defined defaults if not overridden -INCLUDEPATH += $$BOOST_INCLUDE_PATH $$BDB_INCLUDE_PATH $$OPENSSL_INCLUDE_PATH $$QRENCODE_INCLUDE_PATH -LIBS += $$join(BOOST_LIB_PATH,,-L,) $$join(BDB_LIB_PATH,,-L,) $$join(OPENSSL_LIB_PATH,,-L,) $$join(QRENCODE_LIB_PATH,,-L,) -LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX -# -lgdi32 has to happen after -lcrypto (see #681) -win32:LIBS += -lws2_32 -lshlwapi -lmswsock -lole32 -loleaut32 -luuid -lgdi32 -LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX -win32:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX -macx:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX -# Link dynamically against GMP -LIBS += -Wl,-Bdynamic -lgmp - -contains(RELEASE, 1) { - !win32:!macx { - # Linux: turn dynamic linking back on for c/c++ runtime libraries - LIBS += -Wl,-Bdynamic - } -} - -system($$QMAKE_LRELEASE -silent $$TRANSLATIONS) diff --git a/datacoin-qt.pro b/datacoin-qt.pro index f531607f..94152486 100644 --- a/datacoin-qt.pro +++ b/datacoin-qt.pro @@ -9,7 +9,8 @@ CONFIG += no_include_pwd CONFIG += thread # avoid warnings about FD_SETSIZE being redefined -win32:DEFINES += FD_SETSIZE=1024 +# Windows x64 needs BOOST_USE_WINDOWS_H and WIN32_LEAN_AND_MEAN +win32:DEFINES += FD_SETSIZE=1024 BOOST_USE_WINDOWS_H WIN32_LEAN_AND_MEAN WINVER=0x500 # for boost 1.37, add -mt to the boost libraries # use: qmake BOOST_LIB_SUFFIX=-mt @@ -28,9 +29,9 @@ UI_DIR = build # use: qmake "RELEASE=1" contains(RELEASE, 1) { # Mac: compile for maximum compatibility (10.5, 32-bit) - macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk - macx:QMAKE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk - macx:QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.6 -arch i386 -arch x86_64 -isysroot /Developer/SDKs/MacOSX10.6.sdk + macx:QMAKE_CFLAGS += -mmacosx-version-min=10.6 -arch i386 -arch x86_64 -isysroot /Developer/SDKs/MacOSX10.6.sdk + macx:QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.6 -arch i386 -arch x86_64 -isysroot /Developer/SDKs/MacOSX10.6.sdk !win32:!macx { # Linux: static link and extra security (see: https://wiki.debian.org/Hardening) @@ -41,6 +42,13 @@ contains(RELEASE, 1) { } } +macx { + # Always optimize on OS X + QMAKE_CXXFLAGS += -O2 + QMAKE_CFLAGS += -O2 + QMAKE_OBJECTIVE_CFLAGS += -O2 +} + !win32 { # for extra security against potential buffer overflows: enable GCCs Stack Smashing Protection QMAKE_CXXFLAGS *= -fstack-protector-all @@ -52,8 +60,10 @@ contains(RELEASE, 1) { QMAKE_CXXFLAGS *= -D_FORTIFY_SOURCE=2 # for extra security on Windows: enable ASLR and DEP via GCC linker flags win32:QMAKE_LFLAGS *= -Wl,--dynamicbase -Wl,--nxcompat -# on Windows: enable GCC large address aware linker flag -win32:QMAKE_LFLAGS *= -Wl,--large-address-aware +# on Windows x86: enable GCC large address aware linker flag +!contains(QMAKE_HOST.arch, x86_64) { + win32:QMAKE_LFLAGS *= -Wl,--large-address-aware +} # use: qmake "USE_QRCODE=1" # libqrencode (http://fukuchi.org/works/qrencode/index.en.html) must be installed for support @@ -101,7 +111,12 @@ contains(USE_IPV6, -) { contains(BITCOIN_NEED_QT_PLUGINS, 1) { DEFINES += BITCOIN_NEED_QT_PLUGINS - QTPLUGIN += qcncodecs qjpcodecs qtwcodecs qkrcodecs qtaccessiblewidgets + contains(BITCOIN_QT_NO_CODECS, 1) { + DEFINES += BITCOIN_QT_NO_CODECS + } else { + QTPLUGIN += qcncodecs qjpcodecs qtwcodecs qkrcodecs + } + QTPLUGIN += qtaccessiblewidgets } INCLUDEPATH += src/leveldb/include src/leveldb/helpers @@ -418,11 +433,10 @@ LIBS += $$join(BOOST_LIB_PATH,,-L,) $$join(BDB_LIB_PATH,,-L,) $$join(OPENSSL_LIB LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX # -lgdi32 has to happen after -lcrypto (see #681) win32:LIBS += -lws2_32 -lshlwapi -lmswsock -lole32 -loleaut32 -luuid -lgdi32 -LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX -win32:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX -macx:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX +LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX -lboost_chrono$$BOOST_LIB_SUFFIX -lboost_timer$$BOOST_LIB_SUFFIX # Link dynamically against GMP -LIBS += -Wl,-Bdynamic -lgmp +!macx:LIBS += -Wl,-Bdynamic -lgmp +else:LIBS += -lgmp contains(RELEASE, 1) { !win32:!macx { diff --git a/db/autocompact_test.cc b/db/autocompact_test.cc new file mode 100644 index 00000000..d20a2362 --- /dev/null +++ b/db/autocompact_test.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2013 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" +#include "db/db_impl.h" +#include "leveldb/cache.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class AutoCompactTest { + public: + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + AutoCompactTest() { + dbname_ = test::TmpDir() + "/autocompact_test"; + tiny_cache_ = NewLRUCache(100); + options_.block_cache = tiny_cache_; + DestroyDB(dbname_, options_); + options_.create_if_missing = true; + options_.compression = kNoCompression; + ASSERT_OK(DB::Open(options_, dbname_, &db_)); + } + + ~AutoCompactTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete tiny_cache_; + } + + std::string Key(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "key%06d", i); + return std::string(buf); + } + + uint64_t Size(const Slice& start, const Slice& limit) { + Range r(start, limit); + uint64_t size; + db_->GetApproximateSizes(&r, 1, &size); + return size; + } + + void DoReads(int n); +}; + +static const int kValueSize = 200 * 1024; +static const int kTotalSize = 100 * 1024 * 1024; +static const int kCount = kTotalSize / kValueSize; + +// Read through the first n keys repeatedly and check that they get +// compacted (verified by checking the size of the key space). +void AutoCompactTest::DoReads(int n) { + std::string value(kValueSize, 'x'); + DBImpl* dbi = reinterpret_cast(db_); + + // Fill database + for (int i = 0; i < kCount; i++) { + ASSERT_OK(db_->Put(WriteOptions(), Key(i), value)); + } + ASSERT_OK(dbi->TEST_CompactMemTable()); + + // Delete everything + for (int i = 0; i < kCount; i++) { + ASSERT_OK(db_->Delete(WriteOptions(), Key(i))); + } + ASSERT_OK(dbi->TEST_CompactMemTable()); + + // Get initial measurement of the space we will be reading. + const int64_t initial_size = Size(Key(0), Key(n)); + const int64_t initial_other_size = Size(Key(n), Key(kCount)); + + // Read until size drops significantly. + std::string limit_key = Key(n); + for (int read = 0; true; read++) { + ASSERT_LT(read, 100) << "Taking too long to compact"; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); + iter->Valid() && iter->key().ToString() < limit_key; + iter->Next()) { + // Drop data + } + delete iter; + // Wait a little bit to allow any triggered compactions to complete. + Env::Default()->SleepForMicroseconds(1000000); + uint64_t size = Size(Key(0), Key(n)); + fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", + read+1, size/1048576.0, Size(Key(n), Key(kCount))/1048576.0); + if (size <= initial_size/10) { + break; + } + } + + // Verify that the size of the key space not touched by the reads + // is pretty much unchanged. + const int64_t final_other_size = Size(Key(n), Key(kCount)); + ASSERT_LE(final_other_size, initial_other_size + 1048576); + ASSERT_GE(final_other_size, initial_other_size/5 - 1048576); +} + +TEST(AutoCompactTest, ReadAll) { + DoReads(kCount); +} + +TEST(AutoCompactTest, ReadHalf) { + DoReads(kCount/2); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/doc/Doxyfile b/doc/Doxyfile index c32d0f89..72294a82 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -28,13 +28,13 @@ DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. -PROJECT_NAME = Bitcoin +PROJECT_NAME = Datacoin # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.5.0 +PROJECT_NUMBER = 0.8.6 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/doc/README.md b/doc/README.md index ce5f035b..431ef934 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,108 +1,13 @@ -Primecoin High Performance Version -================================== +Datacoin High Performance Version 14 +==================================== -This is the high performance version of Sunny King's Primecoin tree. +This is fork of datacoin-hp by foo1inge (https://github.com/foo1inge/datacoin-hp). +The latest release by the original dev was hp11. +This is the hp14 release (encompassing changes from primecoin-0.1.2-hp14). +Datacoin is a fork of Primecoin (http://primecoin.org) -Features: - * Use GMP for bignum calculations in the mining threads - * Replaced some bignum calculations with 64-bit arithmetic inside the sieve - * Reduced the amount of memory allocations - * L1 and L2 cache optimizations - * Process only 10% of base primes when weaving the sieve - * Configurable sieve size +If you like it, donate: +DTC: DSSHsB1R8mrZd1ujhxcPqQaqAu2cNZsCNn +XPM: AL1nofFch3VPvJYGNYSbKwcW9xhrtyTAAh -Donations are welcome if you want to support my work. - -BTC: 1EaHwHBWeoJtSM2jEdx9Su1NcKvdXbsqxX -LTC: LPD1zDChmqcqKGHFHuLX2JWMMEC5jD5J4j -XPM: AJHjbkVzHhHugd5bpKDtddVDfhtEB8jQZ4 - -Primecoin 0.1.2 BETA -==================== - -Copyright (c) 2013 Primecoin Developers - -Distributed under conditional MIT/X11 software license, see the accompanying -file COPYING. -This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes -cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. - -Intro ---------------------- -Primecoin is a free open source cryptocurrency that implements the first -scientific computing proof-of-work for cryptocurrencies. The unique -proof-of-work design searches for rare prime formations, providing -experimental value for mathematicians to further understand the nature and -distribution related to prime number, a simple yet mysterious construct of -arithmetic that continues to baffle the top minds of mankind. - -Upgrade --------------------- -First backup wallet. Then follow setup instructions. Double check balance -after completing setup and starting up client. - -Setup --------------------- -You need the Qt4 run-time libraries to run Primecoin-Qt. On Debian or Ubuntu: - `sudo apt-get install libqtgui4` - -Unpack the files into a directory and run: - -- bin/32/primecoin-qt (GUI, 32-bit) -- bin/32/primecoind (headless, 32-bit) -- bin/64/primecoin-qt (GUI, 64-bit) -- bin/64/primecoind (headless, 64-bit) - -Website: http://primecoin.org -Forum: http://ppcointalk.org -Github (source code + sig + wiki): https://github.com/primecoin/primecoin -Sourceforge (release builds): https://sourceforge.net/projects/primecoin - - - -Bitcoin 0.8.3 BETA -==================== - -Copyright (c) 2009-2013 Bitcoin Developers - -Distributed under the MIT/X11 software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. -This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes -cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. - - -Intro ---------------------- -Bitcoin is a free open source peer-to-peer electronic cash system that is -completely decentralized, without the need for a central server or trusted -parties. Users hold the crypto keys to their own money and transact directly -with each other, with the help of a P2P network to check for double-spending. - - -Setup ---------------------- -You need the Qt4 run-time libraries to run Bitcoin-Qt. On Debian or Ubuntu: - `sudo apt-get install libqtgui4` - -Unpack the files into a directory and run: - -- bin/32/bitcoin-qt (GUI, 32-bit) -- bin/32/bitcoind (headless, 32-bit) -- bin/64/bitcoin-qt (GUI, 64-bit) -- bin/64/bitcoind (headless, 64-bit) - -See the documentation at the [Bitcoin Wiki](https://en.bitcoin.it/wiki/Main_Page) -for help and more information. - - -Other Pages ---------------------- -- [Unix Build Notes](build-unix.md) -- [OSX Build Notes](build-osx.md) -- [Windows Build Notes](build-msw.md) -- [Coding Guidelines](coding.md) -- [Release Process](release-process.md) -- [Release Notes](release-notes.md) -- [Multiwallet Qt Development](multiwallet-qt.md) -- [Unit Tests](unit-tests.md) -- [Translation Process](translation_process.md) +g1g0 diff --git a/doc/README_windows.txt b/doc/README_windows.txt deleted file mode 100644 index 652c37c4..00000000 --- a/doc/README_windows.txt +++ /dev/null @@ -1,88 +0,0 @@ -Primecoin High Performance Version -================================== - -This is the high performance version of Sunny King's Primecoin tree. - -Features: - * Use GMP for bignum calculations in the mining threads - * Replaced some bignum calculations with 64-bit arithmetic inside the sieve - * Reduced the amount of memory allocations - * L1 and L2 cache optimizations - * Process only 10% of base primes when weaving the sieve - * Configurable sieve size - -Donations are welcome if you want to support my work. - -BTC: 1EaHwHBWeoJtSM2jEdx9Su1NcKvdXbsqxX -LTC: LPD1zDChmqcqKGHFHuLX2JWMMEC5jD5J4j -XPM: AJHjbkVzHhHugd5bpKDtddVDfhtEB8jQZ4 - -Primecoin 0.1.2 BETA -==================== - -Copyright (c) 2013 Primecoin Developers - -Distributed under conditional MIT/X11 software license, see the accompanying -file COPYING. -This product includes software developed by the OpenSSL Project for use in -the OpenSSL Toolkit (http://www.openssl.org/). This product includes -cryptographic software written by Eric Young (eay@cryptsoft.com). - -Intro ---------------------- -Primecoin is a free open source cryptocurrency that implements the first -scientific computing proof-of-work for cryptocurrencies. The unique -proof-of-work design searches for rare prime formations, providing -experimental value for mathematicians to further understand the nature and -distribution related to prime number, a simple yet mysterious construct of -arithmetic that continues to baffle the top minds of mankind. - -Upgrade --------------------- -First backup wallet. Uninstall previous version and then follow setup -instructions. Double check balance after completing setup and starting up -client. - -Setup ------ -Complete windows setup procedure and run Primecoin (Qt). - -Website: http://primecoin.org -Forum: http://ppcointalk.org -Github (source code + sig + wiki): https://github.com/primecoin/primecoin -Sourceforge (release builds): https://sourceforge.net/projects/primecoin - - - -Bitcoin 0.8.3 BETA -================== - -Copyright (c) 2009-2013 Bitcoin Developers - -Distributed under the MIT/X11 software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. -This product includes software developed by the OpenSSL Project for use in -the OpenSSL Toolkit (http://www.openssl.org/). This product includes -cryptographic software written by Eric Young (eay@cryptsoft.com). - - -Intro ------ -Bitcoin is a free open source peer-to-peer electronic cash system that is -completely decentralized, without the need for a central server or trusted -parties. Users hold the crypto keys to their own money and transact directly -with each other, with the help of a P2P network to check for double-spending. - - -Setup ------ -Unpack the files into a directory and run bitcoin-qt.exe. - -Bitcoin-Qt is the original Bitcoin client and it builds the backbone of the network. -However, it downloads and stores the entire history of Bitcoin transactions; -depending on the speed of your computer and network connection, the synchronization -process can take anywhere from a few hours to a day or more. - -See the bitcoin wiki at: - https://en.bitcoin.it/wiki/Main_Page -for more help and information. diff --git a/doc/build-msw.md b/doc/build-msw.md index b7abe288..4f553c4f 100644 --- a/doc/build-msw.md +++ b/doc/build-msw.md @@ -4,7 +4,12 @@ Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. +This product includes the GNU MP Library. +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. See readme-qt.rst for instructions on building Bitcoin-Qt, the graphical user interface. diff --git a/doc/build-osx.md b/doc/build-osx.md index 1fc33b15..9f7e1a52 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -23,6 +23,12 @@ the OpenSSL Toolkit (http://www.openssl.org/). This product includes cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. +This product includes the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your + Notes ----- diff --git a/doc/build-solaris.md b/doc/build-solaris.md index 29057b63..db9f50fb 100644 --- a/doc/build-solaris.md +++ b/doc/build-solaris.md @@ -4,6 +4,11 @@ Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. +This product includes the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your UNIX BUILD NOTES ==================== diff --git a/doc/build-unix.md b/doc/build-unix.md index 6181bb25..2735b8fe 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -4,6 +4,11 @@ Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. +This product includes the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your UNIX BUILD NOTES ==================== diff --git a/doc/changes-primecoin-hp.txt b/doc/changes-primecoin-hp.txt new file mode 100644 index 00000000..0ed85f99 --- /dev/null +++ b/doc/changes-primecoin-hp.txt @@ -0,0 +1,99 @@ +Primecoin High Performance Changelog +==================================== + +Changes in -hp14: + * Huge CPU mining speedup. Up to 73% higher chains/day on Intel's Haswell. + * Developer fee is now 1% (-donationpercentage defaults to 1.0). + * Sieve now uses the BTS instruction (same as RapidPrime miner). + * Added compile-time support for using BMI2 instructions on Haswell. + * Added compile-time support for SSE2 and AVX2 bitwise operations. + * New extended sieve algorithm similar to rdebourbon's beta4 code. + * New default values for the tuning parameters: + . sievefilterprimes defaults to 14000 (up from 7849) + . sievesize defaults to 1376256 (up from 917504) + . sieveextensions defaults to 10 (up from 9) + * Lots of other minor improvements. + +Changes in -hp13: + * Binaries compiled with OpenSSL 1.0.1g which addresses the Heartbleed vulnerability + * Faster blockchain download + +Changes in -hp12: + * IMPORTANT: Fix for multiple machines doing the same work if wallet is shared. + * New chain statistics in debug.log. + * Removed 'primespersec' from the output of getmininginfo. + * Removed 'chainspermin' metric. + * Replaced -sievepercentage parameter with -sievefilterprimes. + * New parameter -l1cachesize for specifying the size of sieve segments. + * Added new blocks/day metric which tries to estimate how many blocks will be found at current difficulty. + * Better automatic adjustment of primorial factor. + * New parameter -primorial for manual adjustment of primorial. + * Implemented early support for v0.2 proposal (needs to be enabled with -miningprotocol=2). + * David's fix for getwork. + * Updated to Bitcoin v0.8.6 codebase. + * Improved the checking of BiTwin chain candidates. As a consequence, short BiTwin chains (1 or 2 primes) are now counted correctly in the mining statistics. Primes/h is now much higher due to this. + * The Qt application is now titled Primecoin High Performance. + * Fixes for Mac OS X and the Clang compiler. + * Revised default sieve parameters. + * Added an automatic donation feature when a new block is found. The -donationpercentage allows a percentage of the block reward to be donated to an address. E.g. passing the command-line parameter -donationpercentage=1.5 will donate 1.5% of every block to the developer. Alternatively, this value can be set in primecoin.conf. Also, the default address can be changed using -donationaddress. + +Changes in -hp11: + * Fixed a bug in the BiTwin filter that was inflating the chains/day estimate and reducing the chances of finding a block (thanks to rdebourbon). + * Slightly improved the accuracy of the prime probability estimate with regards to the 'sieveextensions' parameter. + * Changed the default value of 'sieveextensions' to 9. + * Other small fixes and improvements from cabin. + +Changes in -hp10: + * Major rewrite of the sieve to support extending the sieve (originally implemented by jh000). + * Added a new parameter 'sieveextensions' which controls how many times the sieve is extended. + * Removed the problematic and unnecessary fast-division test. + * Changed the value of nL1CacheElements to 224000 which is slightly faster (thanks to nushor on IRC). + * The 'roundsievepercentage' parameter is gone. The round primorial is now automatically adjusted. + * New RPC command 'listtopprimes' by Sunny. + +Changes in -hp9: + * Sunny's mining optimizations from 0.1.2. + * Minor mining optimizations from mtrlt and gatra. + * Small sieve optimizations for 32-bit processors. + * Sunny's new chains/day estimate. + * Sunny's new 'listprimerecords' RPC command. + * New default value for roundsievepercentage is 70 on mainnet (better chains/day, equal 5-chains/h). + +Changes in -hp8: + * IMPORTANT: Fixed loss of potential blocks caused by fractional length calculation being skipped if fast divisibility test succeeds. (Thanks to mtrlt for spotting this.) + * Skip fractional length calculation for the first number in a chain (as suggested by gatra). + * Added a new configurable round primorial adjustment system. + * Round primorial can be adjusted through the -roundsievepercentage parameter (default value is 30, minimum is 1, maximum is 100). The parameter depends how much time is spent running the sieve. By default 30% of time is spent in the sieve and 70% is spent on checking the candidates produced by the sieve. + * Lots of other performance improvements. + * Bigger sieve sizes should no longer crash on Windows. + * Added new RPC commands setsievepercentage and setroundsievepercentage for changing parameters on the fly. + * GMP is now included as a separate library in the binary releases. + +Changes in -hp7: + * IMPORTANT: Sunny King's fix for mining large block sizes + * Small performance improvement to the sieve + +Changes in -hp6: + * Added fast divisibility tests before doing the expensive Fermat's test + * Lots of other small optimizations + * Introduced a new experimental tuning parameter "sievepercentage". Default value is 10, minimum is 1, maximum is 100. + * Added new RPC command "getchainspermin" + * Added the following information to "getmininginfo": chainspermin, difficulty, sievepercentage, and sievesize + * Attempt to fix the random crash while mining + +Changes in -hp5: + * Added a faster 32-bit routine for inverting numbers + * Other minor performance improvements to the sieve + +Changes in -hp4: + * Added more L1 and L2 cache optimizations + * Some other minor performance improvements (including a change originally by luke-jr) + * New experimental performance metric 5-chains/h in debug.log + +Changes in -hp3: + * Added a new tuning parameter "sievesize". Default value is 1M, minimum is 100k, maximum is 10M. + * Some other minor performance improvements + * Merged two pull requests from geeknik that eliminate references to "Bitcoin" + +Changes in -hp2: + * Restored sieve size to 1,000,000. Quick runs on the testnet show significantly increased probable prime chain rate. Thanks to the numerous people who pointed this out. diff --git a/doc/release-notes.md b/doc/release-notes.md index b458c7c2..2a4874b7 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,91 +1,43 @@ (note: this is a temporary file, to be added-to by anybody, and deleted at release time) -0.8.3 changes +0.8.6 changes ============= -Fix a memory exhaustion attack that could crash low-memory nodes. +- Default block size increase for miners + (see https://gist.github.com/gavinandresen/7670433#086-accept-into-block) -Fix a regression that caused excessive writing of the peers.dat file. +- Remove the all-outputs-must-be-greater-than-CENT-to-qualify-as-free rule for relaying + (see https://gist.github.com/gavinandresen/7670433#086-relaying) +- Lower maximum size for free transaction creation + (see https://gist.github.com/gavinandresen/7670433#086-wallet) -0.8.2 changes -============= - -Fee Policy changes ------------------- - -The default fee for low-priority transactions is lowered from 0.0005 BTC -(for each 1,000 bytes in the transaction; an average transaction is -about 500 bytes) to 0.0001 BTC. - -Payments (transaction outputs) of 0.543 times the minimum relay fee -(0.00005430 BTC) are now considered 'non-standard', because storing them -costs the network more than they are worth and spending them will usually -cost their owner more in transaction fees than they are worth. - -Non-standard transactions are not relayed across the network, are not included -in blocks by most miners, and will not show up in your wallet until they are -included in a block. - -The default fee policy can be overridden using the -mintxfee and -minrelaytxfee -command-line options, but note that we intend to replace the hard-coded fees -with code that automatically calculates and suggests appropriate fees in the -0.9 release and note that if you set a fee policy significantly different from -the rest of the network your transactions may never confirm. - -Bitcoin-Qt changes ------------------- - -- New icon and splash screen -- Improve reporting of synchronization process -- Remove hardcoded fee recommendations -- Improve metadata of executable on MacOSX and Windows -- Move export button to individual tabs instead of toolbar -- Add "send coins" command to context menu in address book -- Add "copy txid" command to copy transaction IDs from transaction overview -- Save & restore window size and position when showing & hiding window -- New translations: Arabic (ar), Bosnian (bs), Catalan (ca), Welsh (cy), Esperanto (eo), Interlingua (la), Latvian (lv) and many improvements to current translations - -MacOSX: - -- OSX support for click-to-pay (bitcoin:) links -- Fix GUI disappearing problem on MacOSX (issue #1522) - -Linux/Unix: - -- Copy addresses to middle-mouse-button clipboard - +- OSX block chain database corruption fixes + - Update leveldb to 1.13 + - Use fcntl with `F_FULLSYNC` instead of fsync on OSX + - Use native Darwin memory barriers + - Replace use of mmap in leveldb for improved reliability (only on OSX) -Command-line options --------------------- +- Fix nodes forwarding transactions with empty vins and getting banned -* `-walletnotify` will call a command on receiving transactions that affect the wallet. -* `-alertnotify` will call a command on receiving an alert from the network. -* `-par` now takes a negative number, to leave a certain amount of cores free. +- Network code performance and robustness improvements -JSON-RPC API changes --------------------- +- Additional debug.log logging for diagnosis of network problems, log timestamps by default -* `listunspent` now lists account and address infromation. -* `getinfo` now also returns the time adjustment estimated from your peers. -* `getpeerinfo` now returns bytessent, bytesrecv and syncnode. -* `gettxoutsetinfo` returns statistics about the unspent transaction output database. -* `gettxout` returns information about a specific unspent transaction output. +- Fix Bitcoin-Qt startup crash when clicking dock icon on OSX +- Fix memory leaks in CKey::SetCompactSignature() and Key::SignCompact() -Networking changes ------------------- +- Fix rare GUI crash on send -* Significant changes to the networking code, reducing latency and memory consumption. -* Avoid initial block download stalling. -* Remove IRC seeding support. -* Performance tweaks. -* Added testnet DNS seeds. +- Various small GUI, documentation and build fixes -Wallet compatibility/rescuing ------------------------------ +Warning +-------- -* Cases where wallets cannot be opened in another version/installation should be reduced. -* `-salvagewallet` now works for encrypted wallets. +- There have been frequent reports of users running out of virtual memory on 32-bit systems + during the initial sync. + Hence it is recommended to use a 64-bit executable if possible. + A 64-bit executable for Windows is planned for 0.9. diff --git a/doc/release-process.md b/doc/release-process.md index 17d6a089..b8aa7d9a 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -31,7 +31,7 @@ Release Process export SIGNER=(your gitian key, ie bluematt, sipa, etc) export VERSION=0.8.0 - cd ./gitian-builder + pushd ./gitian-builder Fetch and build inputs: (first time, or when dependency versions change) @@ -58,13 +58,14 @@ Release Process ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml pushd build/out zip -r bitcoin-${VERSION}-linux-gitian.zip * - mv bitcoin-${VERSION}-linux-gitian.zip ../../ + mv bitcoin-${VERSION}-linux-gitian.zip ../../../ popd ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml pushd build/out zip -r bitcoin-${VERSION}-win32-gitian.zip * - mv bitcoin-${VERSION}-win32-gitian.zip ../../ + mv bitcoin-${VERSION}-win32-gitian.zip ../../../ + popd popd Build output expected: @@ -161,4 +162,4 @@ From a directory containing bitcoin source, gitian.sigs and gitian zips popd - Upload gitian zips to SourceForge -- Celebrate \ No newline at end of file +- Celebrate diff --git a/share/qt/Info.plist b/share/qt/Info.plist index df5ca41b..22eee5a2 100644 --- a/share/qt/Info.plist +++ b/share/qt/Info.plist @@ -3,11 +3,11 @@ CFBundleIconFile - primecoin.icns + datacoin.icns CFBundlePackageType APPL CFBundleGetInfoString - $VERSION, Copyright © 2013-$YEAR The Primecoin developers + $VERSION, Copyright © 2013-$YEAR The Datacoin developers CFBundleShortVersionString $VERSION CFBundleVersion @@ -15,19 +15,19 @@ CFBundleSignature ???? CFBundleExecutable - Primecoin-Qt + Datacoin-HP-Qt CFBundleIdentifier - org.primecoin.Primecoin-Qt + org.datacoin.Datacoin-HP-Qt CFBundleURLTypes CFBundleTypeRole Editor CFBundleURLName - org.primecoin.PrimecoinPayment + org.datacoin.DatacoinPayment CFBundleURLSchemes - primecoin + datacoin diff --git a/share/qt/clean_mac_info_plist.py b/share/qt/clean_mac_info_plist.py index df677f50..57f4946a 100755 --- a/share/qt/clean_mac_info_plist.py +++ b/share/qt/clean_mac_info_plist.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # Jonas Schnelli, 2013 -# make sure the Bitcoin-Qt.app contains the right plist (including the right version) +# make sure the Datacoin-HP-Qt.app contains the right plist (including the right version) # fix made because of serval bugs in Qt mac deployment (https://bugreports.qt-project.org/browse/QTBUG-21267) from string import Template @@ -9,7 +9,7 @@ bitcoinDir = "./"; inFile = bitcoinDir+"/share/qt/Info.plist" -outFile = "Bitcoin-Qt.app/Contents/Info.plist" +outFile = "Datacoin-HP-Qt.app/Contents/Info.plist" version = "unknown"; fileForGrabbingVersion = bitcoinDir+"bitcoin-qt.pro" @@ -26,4 +26,4 @@ fOut = open(outFile, "w"); fOut.write(newFileContent); -print "Info.plist fresh created" \ No newline at end of file +print "Info.plist fresh created" diff --git a/src/alert.cpp b/src/alert.cpp index 42981709..011c58a1 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -243,15 +243,7 @@ bool CAlert::ProcessAlert(bool fThread) // be safe we first strip anything not in safeChars, then add single quotes around // the whole string before passing it to the shell: std::string singleQuote("'"); - // safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything - // even possibly remotely dangerous like & or > - std::string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@"); - std::string safeStatus; - for (std::string::size_type i = 0; i < strStatusBar.size(); i++) - { - if (safeChars.find(strStatusBar[i]) != std::string::npos) - safeStatus.push_back(strStatusBar[i]); - } + std::string safeStatus = SanitizeString(strStatusBar); safeStatus = singleQuote+safeStatus+singleQuote; boost::replace_all(strCmd, "%s", safeStatus); diff --git a/src/bignum.h b/src/bignum.h index 0881807d..44d8ea1b 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -25,13 +25,21 @@ class CAutoBN_CTX protected: BN_CTX* pctx; BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } + inline void must_init() + { + if (!pctx) + { + pctx = BN_CTX_new(); + if (pctx == NULL) + throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); + } + } public: CAutoBN_CTX() { - pctx = BN_CTX_new(); - if (pctx == NULL) - throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); + // Lazy initialization + pctx = NULL; } ~CAutoBN_CTX() @@ -40,9 +48,9 @@ class CAutoBN_CTX BN_CTX_free(pctx); } - operator BN_CTX*() { return pctx; } - BN_CTX& operator*() { return *pctx; } - BN_CTX** operator&() { return &pctx; } + operator BN_CTX*() { must_init(); return pctx; } + BN_CTX& operator*() { must_init(); return *pctx; } + BN_CTX** operator&() { must_init(); return &pctx; } bool operator!() { return (pctx == NULL); } }; @@ -51,6 +59,9 @@ class CAutoBN_CTX class CBigNum : public BIGNUM { public: + // Reusable BN_CTX for better performance + CAutoBN_CTX pctx; + CBigNum() { BN_init(this); @@ -430,7 +441,6 @@ class CBigNum : public BIGNUM CBigNum& operator*=(const CBigNum& b) { - CAutoBN_CTX pctx; if (!BN_mul(this, this, &b, pctx)) throw bignum_error("CBigNum::operator*= : BN_mul failed"); return *this; @@ -540,27 +550,24 @@ inline const CBigNum operator-(const CBigNum& a) inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) { - CAutoBN_CTX pctx; CBigNum r; - if (!BN_mul(&r, &a, &b, pctx)) + if (!BN_mul(&r, &a, &b, r.pctx)) throw bignum_error("CBigNum::operator* : BN_mul failed"); return r; } inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) { - CAutoBN_CTX pctx; CBigNum r; - if (!BN_div(&r, NULL, &a, &b, pctx)) + if (!BN_div(&r, NULL, &a, &b, r.pctx)) throw bignum_error("CBigNum::operator/ : BN_div failed"); return r; } inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) { - CAutoBN_CTX pctx; CBigNum r; - if (!BN_mod(&r, &a, &b, pctx)) + if (!BN_mod(&r, &a, &b, r.pctx)) throw bignum_error("CBigNum::operator% : BN_div failed"); return r; } diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index c3be0a01..a6af0ee9 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -210,12 +210,13 @@ static const CRPCCommand vRPCCommands[] = { "getdifficulty", &getdifficulty, true, false }, { "getgenerate", &getgenerate, true, false }, { "setgenerate", &setgenerate, true, false }, - { "getsievepercentage", &getsievepercentage, true, false }, - { "setsievepercentage", &setsievepercentage, true, false }, + { "getsievesize", &getsievesize, true, false }, + { "setsievesize", &setsievesize, true, false }, + { "getsievefilterprimes", &getsievefilterprimes, true, false }, + { "setsievefilterprimes", &setsievefilterprimes, true, false }, { "getsieveextensions", &getsieveextensions, true, false }, { "setsieveextensions", &setsieveextensions, true, false }, { "getprimespersec", &getprimespersec, true, false }, - { "getchainspermin", &getchainspermin, true, false }, { "getinfo", &getinfo, true, false }, { "getmininginfo", &getmininginfo, true, false }, { "getnewaddress", &getnewaddress, true, false }, @@ -1160,7 +1161,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector 0) ConvertTo(params[0]); if (strMethod == "setgenerate" && n > 0) ConvertTo(params[0]); if (strMethod == "setgenerate" && n > 1) ConvertTo(params[1]); - if (strMethod == "setsievepercentage" && n > 0) ConvertTo(params[0]); + if (strMethod == "setsievesize" && n > 0) ConvertTo(params[0]); + if (strMethod == "setsievefilterprimes" && n > 0) ConvertTo(params[0]); if (strMethod == "setsieveextensions" && n > 0) ConvertTo(params[0]); if (strMethod == "sendtoaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "settxfee" && n > 0) ConvertTo(params[0]); diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index bc5da9c7..f9c8bc73 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -149,12 +149,13 @@ extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool f extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getsievepercentage(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value setsievepercentage(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getsievesize(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value setsievesize(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getsievefilterprimes(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value setsievefilterprimes(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getsieveextensions(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value setsieveextensions(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getprimespersec(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getchainspermin(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp); diff --git a/src/bloom.cpp b/src/bloom.cpp index d9ec2efa..6bdffdbb 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -23,6 +23,8 @@ vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM // The ideal number of hash functions is filter size * ln(2) / number of elements // Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits // See http://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas +isFull(false), +isEmpty(false), nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)), nTweak(nTweakIn), nFlags(nFlagsIn) @@ -37,7 +39,7 @@ inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector< void CBloomFilter::insert(const vector& vKey) { - if (vData.size() == 1 && vData[0] == 0xff) + if (isFull) return; for (unsigned int i = 0; i < nHashFuncs; i++) { @@ -45,6 +47,7 @@ void CBloomFilter::insert(const vector& vKey) // Sets bit nIndex of vData vData[nIndex >> 3] |= bit_mask[7 & nIndex]; } + isEmpty = false; } void CBloomFilter::insert(const COutPoint& outpoint) @@ -63,8 +66,10 @@ void CBloomFilter::insert(const uint256& hash) bool CBloomFilter::contains(const vector& vKey) const { - if (vData.size() == 1 && vData[0] == 0xff) + if (isFull) return true; + if (isEmpty) + return false; for (unsigned int i = 0; i < nHashFuncs; i++) { unsigned int nIndex = Hash(i, vKey); @@ -99,6 +104,10 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& ha bool fFound = false; // Match if the filter contains the hash of tx // for finding tx when they appear in a block + if (isFull) + return true; + if (isEmpty) + return false; if (contains(hash)) fFound = true; @@ -158,3 +167,16 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& ha return false; } + +void CBloomFilter::UpdateEmptyFull() +{ + bool full = true; + bool empty = true; + for (unsigned int i = 0; i < vData.size(); i++) + { + full &= vData[i] == 0xff; + empty &= vData[i] == 0; + } + isFull = full; + isEmpty = empty; +} diff --git a/src/bloom.h b/src/bloom.h index 389ae748..f482bfcc 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -42,6 +42,8 @@ class CBloomFilter { private: std::vector vData; + bool isFull; + bool isEmpty; unsigned int nHashFuncs; unsigned int nTweak; unsigned char nFlags; @@ -57,9 +59,7 @@ class CBloomFilter // It should generally always be a random value (and is largely only exposed for unit testing) // nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK) CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak, unsigned char nFlagsIn); - // Using a filter initialized with this results in undefined behavior - // Should only be used for deserialization - CBloomFilter() {} + CBloomFilter() : isFull(true) {} IMPLEMENT_SERIALIZE ( @@ -83,6 +83,9 @@ class CBloomFilter // Also adds any outputs which match the filter to the filter (to match their spending txes) bool IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash); + + // Checks for empty and full filters to avoid wasting cpu + void UpdateEmptyFull(); }; #endif /* BITCOIN_BLOOM_H */ diff --git a/src/checkpointsync.cpp b/src/checkpointsync.cpp index 9a850551..a03c37b4 100644 --- a/src/checkpointsync.cpp +++ b/src/checkpointsync.cpp @@ -90,6 +90,7 @@ CSyncCheckpoint checkpointMessagePending; uint256 hashInvalidCheckpoint = 0; CCriticalSection cs_hashSyncCheckpoint; std::string strCheckpointWarning; +uint256 hashConnectedBlock = 0; // ppcoin: get last synchronized checkpoint CBlockIndex* GetLastSyncCheckpoint() @@ -223,20 +224,38 @@ bool CheckSyncCheckpoint(const uint256& hashBlock, const CBlockIndex* pindexPrev assert(mapBlockIndex.count(hashSyncCheckpoint)); const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; + const CBlockIndex* pindexConnected = NULL; + if (hashConnectedBlock != 0 && mapBlockIndex.count(hashConnectedBlock)) + pindexConnected = mapBlockIndex[hashConnectedBlock]; + if (nHeight > pindexSync->nHeight) { // trace back to same height as sync-checkpoint const CBlockIndex* pindex = pindexPrev; - while (pindex->nHeight > pindexSync->nHeight) - if (!(pindex = pindex->pprev)) - return error("CheckSyncCheckpoint: pprev null - block index structure failure"); - if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint) - return false; // only descendant of sync-checkpoint can pass check + bool fIsConnected = false; + if (pindexConnected != NULL) + { + while (pindex->nHeight > pindexConnected->nHeight) + if (!(pindex = pindex->pprev)) + return error("CheckSyncCheckpoint: pprev null - block index structure failure"); + if (pindex->nHeight == pindexConnected->nHeight && pindex->GetBlockHash() == hashConnectedBlock) + fIsConnected = true; + } + if (!fIsConnected) + { + while (pindex->nHeight > pindexSync->nHeight) + if (!(pindex = pindex->pprev)) + return error("CheckSyncCheckpoint: pprev null - block index structure failure"); + if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint) + return false; // only descendant of sync-checkpoint can pass check + } } if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint) return false; // same height with sync-checkpoint if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock)) return false; // lower height than sync-checkpoint + if (nHeight > pindexSync->nHeight) + hashConnectedBlock = pindexPrev->GetBlockHash(); return true; } diff --git a/src/checkqueue.h b/src/checkqueue.h index 4be68d16..dd454add 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -168,6 +168,7 @@ template class CCheckQueueControl { // passed queue is supposed to be unused, or NULL if (pqueue != NULL) { pqueue->controlMutex.lock(); + boost::unique_lock lock(pqueue->mutex); assert(pqueue->nTotal == pqueue->nIdle); assert(pqueue->nTodo == 0); assert(pqueue->fAllOk == true); diff --git a/src/clientversion.h b/src/clientversion.h index 3843fd09..10ddc7f4 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -8,7 +8,7 @@ // These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 8 -#define CLIENT_VERSION_REVISION 3 +#define CLIENT_VERSION_REVISION 6 #define CLIENT_VERSION_BUILD 0 // Set to true for release, false for prerelease or test build diff --git a/src/db.cpp b/src/db.cpp index 3133d99b..2bda0659 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -6,7 +6,6 @@ #include "db.h" #include "util.h" #include "main.h" -#include #include #include @@ -541,6 +540,8 @@ bool CAddrDB::Read(CAddrMan& addr) // use file size to size memory buffer int fileSize = GetFilesize(filein); int dataSize = fileSize - sizeof(uint256); + //Don't try to resize to a negative number if file is small + if ( dataSize < 0 ) dataSize = 0; vector vchData; vchData.resize(dataSize); uint256 hashIn; diff --git a/src/init.cpp b/src/init.cpp index db64404e..7e88b1b2 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -93,6 +93,7 @@ static CCoinsViewDB *pcoinsdbview; void Shutdown() { static CCriticalSection cs_Shutdown; + printf("Shutdown : In progress...\n"); TRY_LOCK(cs_Shutdown, lockShutdown); if (!lockShutdown) return; @@ -117,6 +118,7 @@ void Shutdown() boost::filesystem::remove(GetPidFile()); UnregisterWallet(pwalletMain); delete pwalletMain; + printf("Shutdown : done\n"); } // @@ -178,7 +180,7 @@ bool AppInit(int argc, char* argv[]) if (mapArgs.count("-?") || mapArgs.count("--help")) { // First part of help message is specific to bitcoind / RPC client - std::string strUsage = _("Datacoin version") + " " + FormatFullVersion() + "\n\n" + + std::string strUsage = _("Datacoin High Performance version") + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\n" + " datacoind [options] " + "\n" + " datacoind [options] [params] " + _("Send command to -server or datacoind") + "\n" + @@ -339,7 +341,7 @@ std::string HelpMessage() " -testnet " + _("Use the test network") + "\n" + " -debug " + _("Output extra debugging information. Implies all other -debug* options") + "\n" + " -debugnet " + _("Output extra network debugging information") + "\n" + - " -logtimestamps " + _("Prepend debug output with timestamp") + "\n" + + " -logtimestamps " + _("Prepend debug output with timestamp (default: 1)") + "\n" + " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n" + " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n" + #ifdef WIN32 @@ -537,7 +539,7 @@ bool AppInit2(boost::thread_group& threadGroup) // Make sure enough file descriptors are available int nBind = std::max((int)mapArgs.count("-bind"), 1); nMaxConnections = GetArg("-maxconnections", 125); - nMaxConnections = std::max(std::min(nMaxConnections, FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS), 0); + nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); if (nFD < MIN_CORE_FILEDESCRIPTORS) return InitError(_("Not enough file descriptors available.")); @@ -575,7 +577,7 @@ bool AppInit2(boost::thread_group& threadGroup) #endif fPrintToConsole = GetBoolArg("-printtoconsole"); fPrintToDebugger = GetBoolArg("-printtodebugger"); - fLogTimestamps = GetBoolArg("-logtimestamps"); + fLogTimestamps = GetBoolArg("-logtimestamps", true); if (mapArgs.count("-timeout")) { @@ -629,7 +631,7 @@ bool AppInit2(boost::thread_group& threadGroup) if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - printf("Datacoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str()); + printf("Datacoin High Performance version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str()); printf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); if (!fLogTimestamps) printf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h index 28c49ddc..f139dc41 100644 --- a/src/json/json_spirit_writer_template.h +++ b/src/json/json_spirit_writer_template.h @@ -28,7 +28,7 @@ namespace json_spirit template< class String_type > String_type non_printable_to_string( unsigned int c ) { - typedef typename String_type::value_type Char_type; +// typedef typename String_type::value_type Char_type; String_type result( 6, '\\' ); diff --git a/src/key.cpp b/src/key.cpp index 20114e6b..75114c6a 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -328,7 +328,10 @@ bool CKey::SignCompact(uint256 hash, std::vector& vchSig) } if (nRecId == -1) + { + ECDSA_SIG_free(sig); throw key_error("CKey::SignCompact() : unable to construct recoverable key"); + } vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); @@ -367,6 +370,7 @@ bool CKey::SetCompactSignature(uint256 hash, const std::vector& v ECDSA_SIG_free(sig); return true; } + ECDSA_SIG_free(sig); return false; } diff --git a/src/leveldb/.gitignore b/src/leveldb/.gitignore index 55ba072e..71d87a4e 100644 --- a/src/leveldb/.gitignore +++ b/src/leveldb/.gitignore @@ -6,6 +6,7 @@ build_config.mk *.so.* *_test db_bench +leveldbutil Release Debug Benchmark diff --git a/src/leveldb/AUTHORS b/src/leveldb/AUTHORS index 27a9407e..fc40194a 100644 --- a/src/leveldb/AUTHORS +++ b/src/leveldb/AUTHORS @@ -6,3 +6,6 @@ Google Inc. # Initial version authors: Jeffrey Dean Sanjay Ghemawat + +# Partial list of contributors: +Kevin Regan diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile index 42c4952f..20c9c4f2 100644 --- a/src/leveldb/Makefile +++ b/src/leveldb/Makefile @@ -12,7 +12,7 @@ OPT ?= -O2 -DNDEBUG # (A) Production use (optimized mode) #----------------------------------------------- # detect what platform we're building on -$(shell CC=$(CC) CXX=$(CXX) TARGET_OS=$(TARGET_OS) \ +$(shell CC="$(CC)" CXX="$(CXX)" TARGET_OS="$(TARGET_OS)" \ ./build_detect_platform build_config.mk ./) # this file is generated by the previous line to set build flags and sources include build_config.mk @@ -31,6 +31,7 @@ TESTHARNESS = ./util/testharness.o $(TESTUTIL) TESTS = \ arena_test \ + autocompact_test \ bloom_test \ c_test \ cache_test \ @@ -42,6 +43,7 @@ TESTS = \ env_test \ filename_test \ filter_block_test \ + issue178_test \ log_test \ memenv_test \ skiplist_test \ @@ -69,7 +71,7 @@ SHARED = $(SHARED1) else # Update db.h if you change these. SHARED_MAJOR = 1 -SHARED_MINOR = 9 +SHARED_MINOR = 13 SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) SHARED2 = $(SHARED1).$(SHARED_MAJOR) SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR) @@ -113,6 +115,9 @@ leveldbutil: db/leveldb_main.o $(LIBOBJECTS) arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) $(CXX) $(LDFLAGS) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +autocompact_test: db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) $(CXX) $(LDFLAGS) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) @@ -146,6 +151,9 @@ filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) $(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) +issue178_test: issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) $(CXX) $(LDFLAGS) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform index 609cb512..bdfd6417 100755 --- a/src/leveldb/build_detect_platform +++ b/src/leveldb/build_detect_platform @@ -44,6 +44,10 @@ if test -z "$CXX"; then CXX=g++ fi +if test -z "$TMPDIR"; then + TMPDIR=/tmp +fi + # Detect OS if test -z "$TARGET_OS"; then TARGET_OS=`uname -s` @@ -94,6 +98,12 @@ case "$TARGET_OS" in PLATFORM_LIBS="-lpthread" PORT_FILE=port/port_posix.cc ;; + GNU/kFreeBSD) + PLATFORM=OS_KFREEBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_KFREEBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + ;; NetBSD) PLATFORM=OS_NETBSD COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD" @@ -163,8 +173,10 @@ if [ "$CROSS_COMPILE" = "true" ]; then # Cross-compiling; do not try any compilation tests. true else + CXXOUTPUT="${TMPDIR}/leveldb_build_detect_platform-cxx.$$" + # If -std=c++0x works, use . Otherwise use port_posix.h. - $CXX $CXXFLAGS -std=c++0x -x c++ - -o /dev/null 2>/dev/null </dev/null < int main() {} EOF @@ -176,12 +188,14 @@ EOF fi # Test whether tcmalloc is available - $CXX $CXXFLAGS -x c++ - -o /dev/null -ltcmalloc 2>/dev/null </dev/null </dev/null fi PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS" diff --git a/src/leveldb/db/corruption_test.cc b/src/leveldb/db/corruption_test.cc index 31b2d5f4..b37ffdfe 100644 --- a/src/leveldb/db/corruption_test.cc +++ b/src/leveldb/db/corruption_test.cc @@ -35,6 +35,7 @@ class CorruptionTest { CorruptionTest() { tiny_cache_ = NewLRUCache(100); options_.env = &env_; + options_.block_cache = tiny_cache_; dbname_ = test::TmpDir() + "/db_test"; DestroyDB(dbname_, options_); @@ -50,17 +51,14 @@ class CorruptionTest { delete tiny_cache_; } - Status TryReopen(Options* options = NULL) { + Status TryReopen() { delete db_; db_ = NULL; - Options opt = (options ? *options : options_); - opt.env = &env_; - opt.block_cache = tiny_cache_; - return DB::Open(opt, dbname_, &db_); + return DB::Open(options_, dbname_, &db_); } - void Reopen(Options* options = NULL) { - ASSERT_OK(TryReopen(options)); + void Reopen() { + ASSERT_OK(TryReopen()); } void RepairDB() { @@ -92,6 +90,10 @@ class CorruptionTest { for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { uint64_t key; Slice in(iter->key()); + if (in == "" || in == "~") { + // Ignore boundary keys. + continue; + } if (!ConsumeDecimalNumber(&in, &key) || !in.empty() || key < next_expected) { @@ -233,7 +235,7 @@ TEST(CorruptionTest, TableFile) { dbi->TEST_CompactRange(1, NULL, NULL); Corrupt(kTableFile, 100, 1); - Check(99, 99); + Check(90, 99); } TEST(CorruptionTest, TableFileIndexData) { @@ -299,7 +301,7 @@ TEST(CorruptionTest, CompactionInputError) { ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last))); Corrupt(kTableFile, 100, 1); - Check(9, 9); + Check(5, 9); // Force compactions by writing lots of values Build(10000); @@ -307,32 +309,23 @@ TEST(CorruptionTest, CompactionInputError) { } TEST(CorruptionTest, CompactionInputErrorParanoid) { - Options options; - options.paranoid_checks = true; - options.write_buffer_size = 1048576; - Reopen(&options); + options_.paranoid_checks = true; + options_.write_buffer_size = 512 << 10; + Reopen(); DBImpl* dbi = reinterpret_cast(db_); - // Fill levels >= 1 so memtable compaction outputs to level 1 - for (int level = 1; level < config::kNumLevels; level++) { - dbi->Put(WriteOptions(), "", "begin"); - dbi->Put(WriteOptions(), "~", "end"); + // Make multiple inputs so we need to compact. + for (int i = 0; i < 2; i++) { + Build(10); dbi->TEST_CompactMemTable(); + Corrupt(kTableFile, 100, 1); + env_.SleepForMicroseconds(100000); } + dbi->CompactRange(NULL, NULL); - Build(10); - dbi->TEST_CompactMemTable(); - ASSERT_EQ(1, Property("leveldb.num-files-at-level0")); - - Corrupt(kTableFile, 100, 1); - Check(9, 9); - - // Write must eventually fail because of corrupted table - Status s; + // Write must fail because of corrupted table std::string tmp1, tmp2; - for (int i = 0; i < 10000 && s.ok(); i++) { - s = db_->Put(WriteOptions(), Key(i, &tmp1), Value(i, &tmp2)); - } + Status s = db_->Put(WriteOptions(), Key(5, &tmp1), Value(5, &tmp2)); ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db"; } diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc index c9de169f..fa135103 100644 --- a/src/leveldb/db/db_impl.cc +++ b/src/leveldb/db/db_impl.cc @@ -35,6 +35,8 @@ namespace leveldb { +const int kNumNonTableCacheFiles = 10; + // Information kept for every waiting writer struct DBImpl::Writer { Status status; @@ -92,9 +94,9 @@ Options SanitizeOptions(const std::string& dbname, Options result = src; result.comparator = icmp; result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; - ClipToRange(&result.max_open_files, 20, 50000); - ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); - ClipToRange(&result.block_size, 1<<10, 4<<20); + ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000); + ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); + ClipToRange(&result.block_size, 1<<10, 4<<20); if (result.info_log == NULL) { // Open a log file in the same directory as the db src.env->CreateDir(dbname); // In case it does not exist @@ -111,14 +113,14 @@ Options SanitizeOptions(const std::string& dbname, return result; } -DBImpl::DBImpl(const Options& options, const std::string& dbname) - : env_(options.env), - internal_comparator_(options.comparator), - internal_filter_policy_(options.filter_policy), - options_(SanitizeOptions( - dbname, &internal_comparator_, &internal_filter_policy_, options)), - owns_info_log_(options_.info_log != options.info_log), - owns_cache_(options_.block_cache != options.block_cache), +DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) + : env_(raw_options.env), + internal_comparator_(raw_options.comparator), + internal_filter_policy_(raw_options.filter_policy), + options_(SanitizeOptions(dbname, &internal_comparator_, + &internal_filter_policy_, raw_options)), + owns_info_log_(options_.info_log != raw_options.info_log), + owns_cache_(options_.block_cache != raw_options.block_cache), dbname_(dbname), db_lock_(NULL), shutting_down_(NULL), @@ -128,14 +130,16 @@ DBImpl::DBImpl(const Options& options, const std::string& dbname) logfile_(NULL), logfile_number_(0), log_(NULL), + seed_(0), tmp_batch_(new WriteBatch), bg_compaction_scheduled_(false), - manual_compaction_(NULL) { + manual_compaction_(NULL), + consecutive_compaction_errors_(0) { mem_->Ref(); has_imm_.Release_Store(NULL); // Reserve ten files or so for other uses and give the rest to TableCache. - const int table_cache_size = options.max_open_files - 10; + const int table_cache_size = options_.max_open_files - kNumNonTableCacheFiles; table_cache_ = new TableCache(dbname_, &options_, table_cache_size); versions_ = new VersionSet(dbname_, &options_, table_cache_, @@ -310,16 +314,24 @@ Status DBImpl::Recover(VersionEdit* edit) { if (!s.ok()) { return s; } + std::set expected; + versions_->AddLiveFiles(&expected); uint64_t number; FileType type; std::vector logs; for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) - && type == kLogFile - && ((number >= min_log) || (number == prev_log))) { - logs.push_back(number); + if (ParseFileName(filenames[i], &number, &type)) { + expected.erase(number); + if (type == kLogFile && ((number >= min_log) || (number == prev_log))) + logs.push_back(number); } } + if (!expected.empty()) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d missing files; e.g.", + static_cast(expected.size())); + return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin()))); + } // Recover in the order in which the logs were generated std::sort(logs.begin(), logs.end()); @@ -611,6 +623,7 @@ void DBImpl::BackgroundCall() { Status s = BackgroundCompaction(); if (s.ok()) { // Success + consecutive_compaction_errors_ = 0; } else if (shutting_down_.Acquire_Load()) { // Error most likely due to shutdown; do not wait } else { @@ -622,7 +635,12 @@ void DBImpl::BackgroundCall() { Log(options_.info_log, "Waiting after background compaction error: %s", s.ToString().c_str()); mutex_.Unlock(); - env_->SleepForMicroseconds(1000000); + ++consecutive_compaction_errors_; + int seconds_to_sleep = 1; + for (int i = 0; i < 3 && i < consecutive_compaction_errors_ - 1; ++i) { + seconds_to_sleep *= 2; + } + env_->SleepForMicroseconds(seconds_to_sleep * 1000000); mutex_.Lock(); } } @@ -1010,7 +1028,8 @@ static void CleanupIteratorState(void* arg1, void* arg2) { } // namespace Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, - SequenceNumber* latest_snapshot) { + SequenceNumber* latest_snapshot, + uint32_t* seed) { IterState* cleanup = new IterState; mutex_.Lock(); *latest_snapshot = versions_->LastSequence(); @@ -1034,13 +1053,15 @@ Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, cleanup->version = versions_->current(); internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL); + *seed = ++seed_; mutex_.Unlock(); return internal_iter; } Iterator* DBImpl::TEST_NewInternalIterator() { SequenceNumber ignored; - return NewInternalIterator(ReadOptions(), &ignored); + uint32_t ignored_seed; + return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed); } int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { @@ -1097,12 +1118,21 @@ Status DBImpl::Get(const ReadOptions& options, Iterator* DBImpl::NewIterator(const ReadOptions& options) { SequenceNumber latest_snapshot; - Iterator* internal_iter = NewInternalIterator(options, &latest_snapshot); + uint32_t seed; + Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed); return NewDBIterator( - &dbname_, env_, user_comparator(), internal_iter, + this, user_comparator(), iter, (options.snapshot != NULL ? reinterpret_cast(options.snapshot)->number_ - : latest_snapshot)); + : latest_snapshot), + seed); +} + +void DBImpl::RecordReadSample(Slice key) { + MutexLock l(&mutex_); + if (versions_->current()->RecordReadSample(key)) { + MaybeScheduleCompaction(); + } } const Snapshot* DBImpl::GetSnapshot() { @@ -1268,10 +1298,11 @@ Status DBImpl::MakeRoomForWrite(bool force) { } else if (imm_ != NULL) { // We have filled up the current memtable, but the previous // one is still being compacted, so we wait. + Log(options_.info_log, "Current memtable full; waiting...\n"); bg_cv_.Wait(); } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { // There are too many level-0 files. - Log(options_.info_log, "waiting...\n"); + Log(options_.info_log, "Too many L0 files; waiting...\n"); bg_cv_.Wait(); } else { // Attempt to switch to a new memtable and trigger compaction of old diff --git a/src/leveldb/db/db_impl.h b/src/leveldb/db/db_impl.h index bd29dd80..75fd30ab 100644 --- a/src/leveldb/db/db_impl.h +++ b/src/leveldb/db/db_impl.h @@ -59,13 +59,19 @@ class DBImpl : public DB { // file at a level >= 1. int64_t TEST_MaxNextLevelOverlappingBytes(); + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. + void RecordReadSample(Slice key); + private: friend class DB; struct CompactionState; struct Writer; Iterator* NewInternalIterator(const ReadOptions&, - SequenceNumber* latest_snapshot); + SequenceNumber* latest_snapshot, + uint32_t* seed); Status NewDB(); @@ -135,6 +141,7 @@ class DBImpl : public DB { WritableFile* logfile_; uint64_t logfile_number_; log::Writer* log_; + uint32_t seed_; // For sampling. // Queue of writers. std::deque writers_; @@ -163,6 +170,7 @@ class DBImpl : public DB { // Have we encountered a background error in paranoid mode? Status bg_error_; + int consecutive_compaction_errors_; // Per level compaction stats. stats_[level] stores the stats for // compactions that produced data for the specified "level". diff --git a/src/leveldb/db/db_iter.cc b/src/leveldb/db/db_iter.cc index 87dca2de..071a54e3 100644 --- a/src/leveldb/db/db_iter.cc +++ b/src/leveldb/db/db_iter.cc @@ -5,12 +5,14 @@ #include "db/db_iter.h" #include "db/filename.h" +#include "db/db_impl.h" #include "db/dbformat.h" #include "leveldb/env.h" #include "leveldb/iterator.h" #include "port/port.h" #include "util/logging.h" #include "util/mutexlock.h" +#include "util/random.h" namespace leveldb { @@ -46,15 +48,16 @@ class DBIter: public Iterator { kReverse }; - DBIter(const std::string* dbname, Env* env, - const Comparator* cmp, Iterator* iter, SequenceNumber s) - : dbname_(dbname), - env_(env), + DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNumber s, + uint32_t seed) + : db_(db), user_comparator_(cmp), iter_(iter), sequence_(s), direction_(kForward), - valid_(false) { + valid_(false), + rnd_(seed), + bytes_counter_(RandomPeriod()) { } virtual ~DBIter() { delete iter_; @@ -100,8 +103,12 @@ class DBIter: public Iterator { } } - const std::string* const dbname_; - Env* const env_; + // Pick next gap with average value of config::kReadBytesPeriod. + ssize_t RandomPeriod() { + return rnd_.Uniform(2*config::kReadBytesPeriod); + } + + DBImpl* db_; const Comparator* const user_comparator_; Iterator* const iter_; SequenceNumber const sequence_; @@ -112,13 +119,23 @@ class DBIter: public Iterator { Direction direction_; bool valid_; + Random rnd_; + ssize_t bytes_counter_; + // No copying allowed DBIter(const DBIter&); void operator=(const DBIter&); }; inline bool DBIter::ParseKey(ParsedInternalKey* ikey) { - if (!ParseInternalKey(iter_->key(), ikey)) { + Slice k = iter_->key(); + ssize_t n = k.size() + iter_->value().size(); + bytes_counter_ -= n; + while (bytes_counter_ < 0) { + bytes_counter_ += RandomPeriod(); + db_->RecordReadSample(k); + } + if (!ParseInternalKey(k, ikey)) { status_ = Status::Corruption("corrupted internal key in DBIter"); return false; } else { @@ -288,12 +305,12 @@ void DBIter::SeekToLast() { } // anonymous namespace Iterator* NewDBIterator( - const std::string* dbname, - Env* env, + DBImpl* db, const Comparator* user_key_comparator, Iterator* internal_iter, - const SequenceNumber& sequence) { - return new DBIter(dbname, env, user_key_comparator, internal_iter, sequence); + SequenceNumber sequence, + uint32_t seed) { + return new DBIter(db, user_key_comparator, internal_iter, sequence, seed); } } // namespace leveldb diff --git a/src/leveldb/db/db_iter.h b/src/leveldb/db/db_iter.h index d9e1b174..04927e93 100644 --- a/src/leveldb/db/db_iter.h +++ b/src/leveldb/db/db_iter.h @@ -11,15 +11,17 @@ namespace leveldb { +class DBImpl; + // Return a new iterator that converts internal keys (yielded by // "*internal_iter") that were live at the specified "sequence" number // into appropriate user keys. extern Iterator* NewDBIterator( - const std::string* dbname, - Env* env, + DBImpl* db, const Comparator* user_key_comparator, Iterator* internal_iter, - const SequenceNumber& sequence); + SequenceNumber sequence, + uint32_t seed); } // namespace leveldb diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc index 684ea3bd..49aae04d 100644 --- a/src/leveldb/db/db_test.cc +++ b/src/leveldb/db/db_test.cc @@ -33,8 +33,11 @@ class AtomicCounter { public: AtomicCounter() : count_(0) { } void Increment() { + IncrementBy(1); + } + void IncrementBy(int count) { MutexLock l(&mu_); - count_++; + count_ += count; } int Read() { MutexLock l(&mu_); @@ -45,6 +48,10 @@ class AtomicCounter { count_ = 0; } }; + +void DelayMilliseconds(int millis) { + Env::Default()->SleepForMicroseconds(millis * 1000); +} } // Special Env used to delay background operations @@ -69,6 +76,7 @@ class SpecialEnv : public EnvWrapper { AtomicCounter random_read_counter_; AtomicCounter sleep_counter_; + AtomicCounter sleep_time_counter_; explicit SpecialEnv(Env* base) : EnvWrapper(base) { delay_sstable_sync_.Release_Store(NULL); @@ -103,7 +111,7 @@ class SpecialEnv : public EnvWrapper { Status Flush() { return base_->Flush(); } Status Sync() { while (env_->delay_sstable_sync_.Acquire_Load() != NULL) { - env_->SleepForMicroseconds(100000); + DelayMilliseconds(100); } return base_->Sync(); } @@ -174,8 +182,9 @@ class SpecialEnv : public EnvWrapper { virtual void SleepForMicroseconds(int micros) { sleep_counter_.Increment(); - target()->SleepForMicroseconds(micros); + sleep_time_counter_.IncrementBy(micros); } + }; class DBTest { @@ -461,6 +470,20 @@ class DBTest { } return result; } + + bool DeleteAnSSTFile() { + std::vector filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { + ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number))); + return true; + } + } + return false; + } }; TEST(DBTest, Empty) { @@ -611,7 +634,7 @@ TEST(DBTest, GetEncountersEmptyLevel) { } // Step 4: Wait for compaction to finish - env_->SleepForMicroseconds(1000000); + DelayMilliseconds(1000); ASSERT_EQ(NumTableFilesAtLevel(0), 0); } while (ChangeOptions()); @@ -1295,7 +1318,7 @@ TEST(DBTest, L0_CompactionBug_Issue44_a) { Reopen(); Reopen(); ASSERT_EQ("(a->v)", Contents()); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + DelayMilliseconds(1000); // Wait for compaction to finish ASSERT_EQ("(a->v)", Contents()); } @@ -1311,7 +1334,7 @@ TEST(DBTest, L0_CompactionBug_Issue44_b) { Put("",""); Reopen(); Put("",""); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + DelayMilliseconds(1000); // Wait for compaction to finish Reopen(); Put("d","dv"); Reopen(); @@ -1321,7 +1344,7 @@ TEST(DBTest, L0_CompactionBug_Issue44_b) { Delete("b"); Reopen(); ASSERT_EQ("(->)(c->cv)", Contents()); - env_->SleepForMicroseconds(1000000); // Wait for compaction to finish + DelayMilliseconds(1000); // Wait for compaction to finish ASSERT_EQ("(->)(c->cv)", Contents()); } @@ -1506,6 +1529,30 @@ TEST(DBTest, NoSpace) { ASSERT_GE(env_->sleep_counter_.Read(), 5); } +TEST(DBTest, ExponentialBackoff) { + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + Compact("a", "z"); + env_->non_writable_.Release_Store(env_); // Force errors for new files + env_->sleep_counter_.Reset(); + env_->sleep_time_counter_.Reset(); + for (int i = 0; i < 5; i++) { + dbfull()->TEST_CompactRange(2, NULL, NULL); + } + env_->non_writable_.Release_Store(NULL); + + // Wait for compaction to finish + DelayMilliseconds(1000); + + ASSERT_GE(env_->sleep_counter_.Read(), 5); + ASSERT_LT(env_->sleep_counter_.Read(), 10); + ASSERT_GE(env_->sleep_time_counter_.Read(), 10e6); +} + TEST(DBTest, NonWritableFileSystem) { Options options = CurrentOptions(); options.write_buffer_size = 1000; @@ -1519,7 +1566,7 @@ TEST(DBTest, NonWritableFileSystem) { fprintf(stderr, "iter %d; errors %d\n", i, errors); if (!Put("foo", big).ok()) { errors++; - env_->SleepForMicroseconds(100000); + DelayMilliseconds(100); } } ASSERT_GT(errors, 0); @@ -1567,6 +1614,24 @@ TEST(DBTest, ManifestWriteError) { } } +TEST(DBTest, MissingSSTFile) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Dump the memtable to disk. + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + + Close(); + ASSERT_TRUE(DeleteAnSSTFile()); + Options options = CurrentOptions(); + options.paranoid_checks = true; + Status s = TryReopen(&options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("issing") != std::string::npos) + << s.ToString(); +} + TEST(DBTest, FilesDeletedAfterCompaction) { ASSERT_OK(Put("foo", "v2")); Compact("a", "z"); @@ -1711,13 +1776,13 @@ TEST(DBTest, MultiThreaded) { } // Let them run for a while - env_->SleepForMicroseconds(kTestSeconds * 1000000); + DelayMilliseconds(kTestSeconds * 1000); // Stop the threads and wait for them to finish mt.stop.Release_Store(&mt); for (int id = 0; id < kNumThreads; id++) { while (mt.thread_done[id].Acquire_Load() == NULL) { - env_->SleepForMicroseconds(100000); + DelayMilliseconds(100); } } } while (ChangeOptions()); diff --git a/src/leveldb/db/dbformat.cc b/src/leveldb/db/dbformat.cc index 28e11b39..20a7ca44 100644 --- a/src/leveldb/db/dbformat.cc +++ b/src/leveldb/db/dbformat.cc @@ -26,7 +26,7 @@ std::string ParsedInternalKey::DebugString() const { (unsigned long long) sequence, int(type)); std::string result = "'"; - result += user_key.ToString(); + result += EscapeString(user_key.ToString()); result += buf; return result; } diff --git a/src/leveldb/db/dbformat.h b/src/leveldb/db/dbformat.h index f7f64daf..5d8a032b 100644 --- a/src/leveldb/db/dbformat.h +++ b/src/leveldb/db/dbformat.h @@ -38,6 +38,9 @@ static const int kL0_StopWritesTrigger = 12; // space if the same key space is being repeatedly overwritten. static const int kMaxMemCompactLevel = 2; +// Approximate gap in bytes between samples of data read during iteration. +static const int kReadBytesPeriod = 1048576; + } // namespace config class InternalKey; diff --git a/src/leveldb/db/filename_test.cc b/src/leveldb/db/filename_test.cc index 47353d6c..5a26da47 100644 --- a/src/leveldb/db/filename_test.cc +++ b/src/leveldb/db/filename_test.cc @@ -70,7 +70,7 @@ TEST(FileNameTest, Parse) { for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) { std::string f = errors[i]; ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f; - }; + } } TEST(FileNameTest, Construction) { diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc index 7d0a5de2..66d73be7 100644 --- a/src/leveldb/db/version_set.cc +++ b/src/leveldb/db/version_set.cc @@ -289,6 +289,51 @@ static bool NewestFirst(FileMetaData* a, FileMetaData* b) { return a->number > b->number; } +void Version::ForEachOverlapping(Slice user_key, Slice internal_key, + void* arg, + bool (*func)(void*, int, FileMetaData*)) { + // TODO(sanjay): Change Version::Get() to use this function. + const Comparator* ucmp = vset_->icmp_.user_comparator(); + + // Search level-0 in order from newest to oldest. + std::vector tmp; + tmp.reserve(files_[0].size()); + for (uint32_t i = 0; i < files_[0].size(); i++) { + FileMetaData* f = files_[0][i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (!tmp.empty()) { + std::sort(tmp.begin(), tmp.end(), NewestFirst); + for (uint32_t i = 0; i < tmp.size(); i++) { + if (!(*func)(arg, 0, tmp[i])) { + return; + } + } + } + + // Search other levels. + for (int level = 1; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Binary search to find earliest index whose largest key >= internal_key. + uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key); + if (index < num_files) { + FileMetaData* f = files_[level][index]; + if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) { + // All of "f" is past any data for user_key + } else { + if (!(*func)(arg, level, f)) { + return; + } + } + } + } +} + Status Version::Get(const ReadOptions& options, const LookupKey& k, std::string* value, @@ -401,6 +446,44 @@ bool Version::UpdateStats(const GetStats& stats) { return false; } +bool Version::RecordReadSample(Slice internal_key) { + ParsedInternalKey ikey; + if (!ParseInternalKey(internal_key, &ikey)) { + return false; + } + + struct State { + GetStats stats; // Holds first matching file + int matches; + + static bool Match(void* arg, int level, FileMetaData* f) { + State* state = reinterpret_cast(arg); + state->matches++; + if (state->matches == 1) { + // Remember first match. + state->stats.seek_file = f; + state->stats.seek_file_level = level; + } + // We can stop iterating once we have a second match. + return state->matches < 2; + } + }; + + State state; + state.matches = 0; + ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match); + + // Must have at least two matches since we want to merge across + // files. But what if we have a single file that contains many + // overwrites and deletions? Should we have another mechanism for + // finding such files? + if (state.matches >= 2) { + // 1MB cost is about 1 seek (see comment in Builder::Apply). + return UpdateStats(state.stats); + } + return false; +} + void Version::Ref() { ++refs_; } @@ -435,10 +518,13 @@ int Version::PickLevelForMemTableOutput( if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) { break; } - GetOverlappingInputs(level + 2, &start, &limit, &overlaps); - const int64_t sum = TotalFileSize(overlaps); - if (sum > kMaxGrandParentOverlapBytes) { - break; + if (level + 2 < config::kNumLevels) { + // Check that file does not overlap too many grandparent bytes. + GetOverlappingInputs(level + 2, &start, &limit, &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > kMaxGrandParentOverlapBytes) { + break; + } } level++; } @@ -452,6 +538,8 @@ void Version::GetOverlappingInputs( const InternalKey* begin, const InternalKey* end, std::vector* inputs) { + assert(level >= 0); + assert(level < config::kNumLevels); inputs->clear(); Slice user_begin, user_end; if (begin != NULL) { @@ -1331,14 +1419,19 @@ Compaction* VersionSet::CompactRange( } // Avoid compacting too much in one shot in case the range is large. - const uint64_t limit = MaxFileSizeForLevel(level); - uint64_t total = 0; - for (size_t i = 0; i < inputs.size(); i++) { - uint64_t s = inputs[i]->file_size; - total += s; - if (total >= limit) { - inputs.resize(i + 1); - break; + // But we cannot do this for level-0 since level-0 files can overlap + // and we must not pick one file and drop another older file if the + // two files overlap. + if (level > 0) { + const uint64_t limit = MaxFileSizeForLevel(level); + uint64_t total = 0; + for (size_t i = 0; i < inputs.size(); i++) { + uint64_t s = inputs[i]->file_size; + total += s; + if (total >= limit) { + inputs.resize(i + 1); + break; + } } } diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h index 9d084fdb..20de0e26 100644 --- a/src/leveldb/db/version_set.h +++ b/src/leveldb/db/version_set.h @@ -78,6 +78,12 @@ class Version { // REQUIRES: lock is held bool UpdateStats(const GetStats& stats); + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. Returns true if a new compaction may need to be triggered. + // REQUIRES: lock is held + bool RecordReadSample(Slice key); + // Reference count management (so Versions do not disappear out from // under live iterators) void Ref(); @@ -114,6 +120,15 @@ class Version { class LevelFileNumIterator; Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const; + // Call func(arg, level, f) for every file that overlaps user_key in + // order from newest to oldest. If an invocation of func returns + // false, makes no more calls. + // + // REQUIRES: user portion of internal_key == user_key. + void ForEachOverlapping(Slice user_key, Slice internal_key, + void* arg, + bool (*func)(void*, int, FileMetaData*)); + VersionSet* vset_; // VersionSet to which this Version belongs Version* next_; // Next version in linked list Version* prev_; // Previous version in linked list diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h index 29d36744..57c00a5d 100644 --- a/src/leveldb/include/leveldb/db.h +++ b/src/leveldb/include/leveldb/db.h @@ -14,7 +14,7 @@ namespace leveldb { // Update Makefile if you change these static const int kMajorVersion = 1; -static const int kMinorVersion = 9; +static const int kMinorVersion = 13; struct Options; struct ReadOptions; diff --git a/src/leveldb/issues/issue178_test.cc b/src/leveldb/issues/issue178_test.cc new file mode 100644 index 00000000..1b1cf8bb --- /dev/null +++ b/src/leveldb/issues/issue178_test.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2013 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// Test for issue 178: a manual compaction causes deleted data to reappear. +#include +#include +#include + +#include "leveldb/db.h" +#include "leveldb/write_batch.h" +#include "util/testharness.h" + +namespace { + +const int kNumKeys = 1100000; + +std::string Key1(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "my_key_%d", i); + return buf; +} + +std::string Key2(int i) { + return Key1(i) + "_xxx"; +} + +class Issue178 { }; + +TEST(Issue178, Test) { + // Get rid of any state from an old run. + std::string dbpath = leveldb::test::TmpDir() + "/leveldb_cbug_test"; + DestroyDB(dbpath, leveldb::Options()); + + // Open database. Disable compression since it affects the creation + // of layers and the code below is trying to test against a very + // specific scenario. + leveldb::DB* db; + leveldb::Options db_options; + db_options.create_if_missing = true; + db_options.compression = leveldb::kNoCompression; + ASSERT_OK(leveldb::DB::Open(db_options, dbpath, &db)); + + // create first key range + leveldb::WriteBatch batch; + for (size_t i = 0; i < kNumKeys; i++) { + batch.Put(Key1(i), "value for range 1 key"); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // create second key range + batch.Clear(); + for (size_t i = 0; i < kNumKeys; i++) { + batch.Put(Key2(i), "value for range 2 key"); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // delete second key range + batch.Clear(); + for (size_t i = 0; i < kNumKeys; i++) { + batch.Delete(Key2(i)); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // compact database + std::string start_key = Key1(0); + std::string end_key = Key1(kNumKeys - 1); + leveldb::Slice least(start_key.data(), start_key.size()); + leveldb::Slice greatest(end_key.data(), end_key.size()); + + // commenting out the line below causes the example to work correctly + db->CompactRange(&least, &greatest); + + // count the keys + leveldb::Iterator* iter = db->NewIterator(leveldb::ReadOptions()); + size_t num_keys = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + num_keys++; + } + delete iter; + ASSERT_EQ(kNumKeys, num_keys) << "Bad number of keys"; + + // close database + delete db; + DestroyDB(dbpath, leveldb::Options()); +} + +} // anonymous namespace + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h index e17bf435..844fba25 100644 --- a/src/leveldb/port/atomic_pointer.h +++ b/src/leveldb/port/atomic_pointer.h @@ -50,6 +50,13 @@ namespace port { // http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx #define LEVELDB_HAVE_MEMORY_BARRIER +// Mac OS +#elif defined(OS_MACOSX) +inline void MemoryBarrier() { + OSMemoryBarrier(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + // Gcc on x86 #elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__) inline void MemoryBarrier() { @@ -62,19 +69,12 @@ inline void MemoryBarrier() { // Sun Studio #elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC) inline void MemoryBarrier() { - // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. asm volatile("" : : : "memory"); } #define LEVELDB_HAVE_MEMORY_BARRIER -// Mac OS -#elif defined(OS_MACOSX) -inline void MemoryBarrier() { - OSMemoryBarrier(); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - // ARM Linux #elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__) typedef void (*LinuxKernelMemoryBarrierFunc)(void); diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h index f2b89bff..21c845e2 100644 --- a/src/leveldb/port/port_posix.h +++ b/src/leveldb/port/port_posix.h @@ -62,12 +62,16 @@ #define fflush_unlocked fflush #endif -#if defined(OS_MACOSX) || defined(OS_FREEBSD) ||\ +#if defined(OS_FREEBSD) ||\ defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) // Use fsync() on platforms without fdatasync() #define fdatasync fsync #endif +#if defined(OS_MACOSX) +#define fdatasync(fd) fcntl(fd, F_FULLFSYNC, 0) +#endif + #if defined(OS_ANDROID) && __ANDROID_API__ < 9 // fdatasync() was only introduced in API level 9 on Android. Use fsync() // when targetting older platforms. diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc index 99c1d8e3..1b0f060a 100644 --- a/src/leveldb/port/port_win.cc +++ b/src/leveldb/port/port_win.cc @@ -109,12 +109,10 @@ void CondVar::Signal() { void CondVar::SignalAll() { wait_mtx_.Lock(); - for(long i = 0; i < waiting_; ++i) { - ::ReleaseSemaphore(sem1_, 1, NULL); - while(waiting_ > 0) { - --waiting_; - ::WaitForSingleObject(sem2_, INFINITE); - } + ::ReleaseSemaphore(sem1_, waiting_, NULL); + while(waiting_ > 0) { + --waiting_; + ::WaitForSingleObject(sem2_, INFINITE); } wait_mtx_.Unlock(); } diff --git a/src/leveldb/table/block.cc b/src/leveldb/table/block.cc index ab83c111..79ea9d9e 100644 --- a/src/leveldb/table/block.cc +++ b/src/leveldb/table/block.cc @@ -16,7 +16,7 @@ namespace leveldb { inline uint32_t Block::NumRestarts() const { - assert(size_ >= 2*sizeof(uint32_t)); + assert(size_ >= sizeof(uint32_t)); return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); } @@ -27,11 +27,12 @@ Block::Block(const BlockContents& contents) if (size_ < sizeof(uint32_t)) { size_ = 0; // Error marker } else { - restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); - if (restart_offset_ > size_ - sizeof(uint32_t)) { - // The size is too small for NumRestarts() and therefore - // restart_offset_ wrapped around. + size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t); + if (NumRestarts() > max_restarts_allowed) { + // The size is too small for NumRestarts() size_ = 0; + } else { + restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); } } } @@ -253,7 +254,7 @@ class Block::Iter : public Iterator { }; Iterator* Block::NewIterator(const Comparator* cmp) { - if (size_ < 2*sizeof(uint32_t)) { + if (size_ < sizeof(uint32_t)) { return NewErrorIterator(Status::Corruption("bad block contents")); } const uint32_t num_restarts = NumRestarts(); diff --git a/src/leveldb/table/table.cc b/src/leveldb/table/table.cc index dbd6d3a1..71c1756e 100644 --- a/src/leveldb/table/table.cc +++ b/src/leveldb/table/table.cc @@ -228,7 +228,6 @@ Status Table::InternalGet(const ReadOptions& options, const Slice& k, !filter->KeyMayMatch(handle.offset(), k)) { // Not found } else { - Slice handle = iiter->value(); Iterator* block_iter = BlockReader(this, options, iiter->value()); block_iter->Seek(k); if (block_iter->Valid()) { diff --git a/src/leveldb/table/table_test.cc b/src/leveldb/table/table_test.cc index 57cea253..c723bf84 100644 --- a/src/leveldb/table/table_test.cc +++ b/src/leveldb/table/table_test.cc @@ -644,6 +644,36 @@ class Harness { Constructor* constructor_; }; +// Test empty table/block. +TEST(Harness, Empty) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Test(&rnd); + } +} + +// Special test for a block with no restart entries. The C++ leveldb +// code never generates such blocks, but the Java version of leveldb +// seems to. +TEST(Harness, ZeroRestartPointsInBlock) { + char data[sizeof(uint32_t)]; + memset(data, 0, sizeof(data)); + BlockContents contents; + contents.data = Slice(data, sizeof(data)); + contents.cachable = false; + contents.heap_allocated = false; + Block block(contents); + Iterator* iter = block.NewIterator(BytewiseComparator()); + iter->SeekToFirst(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + ASSERT_TRUE(!iter->Valid()); + iter->Seek("foo"); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + // Test the empty key TEST(Harness, SimpleEmptyKey) { for (int i = 0; i < kNumTestArgs; i++) { diff --git a/src/leveldb/util/cache.cc b/src/leveldb/util/cache.cc index 24f1f63f..8b197bc0 100644 --- a/src/leveldb/util/cache.cc +++ b/src/leveldb/util/cache.cc @@ -116,7 +116,6 @@ class HandleTable { LRUHandle* h = list_[i]; while (h != NULL) { LRUHandle* next = h->next_hash; - Slice key = h->key(); uint32_t hash = h->hash; LRUHandle** ptr = &new_list[hash & (new_length - 1)]; h->next_hash = *ptr; @@ -160,7 +159,6 @@ class LRUCache { // mutex_ protects the following state. port::Mutex mutex_; size_t usage_; - uint64_t last_id_; // Dummy head of LRU list. // lru.prev is newest entry, lru.next is oldest entry. @@ -170,8 +168,7 @@ class LRUCache { }; LRUCache::LRUCache() - : usage_(0), - last_id_(0) { + : usage_(0) { // Make empty circular linked list lru_.next = &lru_; lru_.prev = &lru_; diff --git a/src/leveldb/util/coding_test.cc b/src/leveldb/util/coding_test.cc index 2c52b17b..fb5726e3 100644 --- a/src/leveldb/util/coding_test.cc +++ b/src/leveldb/util/coding_test.cc @@ -109,7 +109,7 @@ TEST(Coding, Varint64) { values.push_back(power); values.push_back(power-1); values.push_back(power+1); - }; + } std::string s; for (int i = 0; i < values.size(); i++) { diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc index db81f56d..aff5df9d 100644 --- a/src/leveldb/util/env_posix.cc +++ b/src/leveldb/util/env_posix.cc @@ -320,8 +320,39 @@ class PosixMmapFile : public WritableFile { return Status::OK(); } - virtual Status Sync() { + Status SyncDirIfManifest() { + const char* f = filename_.c_str(); + const char* sep = strrchr(f, '/'); + Slice basename; + std::string dir; + if (sep == NULL) { + dir = "."; + basename = f; + } else { + dir = std::string(f, sep - f); + basename = sep + 1; + } Status s; + if (basename.starts_with("MANIFEST")) { + int fd = open(dir.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(dir, errno); + } else { + if (fsync(fd) < 0) { + s = IOError(dir, errno); + } + close(fd); + } + } + return s; + } + + virtual Status Sync() { + // Ensure new files referred to by the manifest are in the filesystem. + Status s = SyncDirIfManifest(); + if (!s.ok()) { + return s; + } if (pending_sync_) { // Some unmapped data was not synced @@ -346,6 +377,93 @@ class PosixMmapFile : public WritableFile { } }; +#if defined(OS_MACOSX) +class PosixWriteableFile : public WritableFile { + private: + std::string filename_; + int fd_; + public: + PosixWriteableFile(const std::string& fname, int fd) + : filename_(fname), + fd_(fd) + { } + + + ~PosixWriteableFile() { + if (fd_ >= 0) { + PosixWriteableFile::Close(); + } + } + + virtual Status Append(const Slice& data) { + Status s; + int ret; + ret = write(fd_, data.data(), data.size()); + if (ret < 0) { + s = IOError(filename_, errno); + } else if (ret < data.size()) { + s = Status::IOError(filename_, "short write"); + } + + return s; + } + + virtual Status Close() { + Status s; + if (close(fd_) < 0) { + s = IOError(filename_, errno); + } + fd_ = -1; + return s; + } + + virtual Status Flush() { + return Status::OK(); + } + + Status SyncDirIfManifest() { + const char* f = filename_.c_str(); + const char* sep = strrchr(f, '/'); + Slice basename; + std::string dir; + if (sep == NULL) { + dir = "."; + basename = f; + } else { + dir = std::string(f, sep - f); + basename = sep + 1; + } + Status s; + if (basename.starts_with("MANIFEST")) { + int fd = open(dir.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(dir, errno); + } else { + if (fsync(fd) < 0) { + s = IOError(dir, errno); + } + close(fd); + } + } + return s; + } + + virtual Status Sync() { + // Ensure new files referred to by the manifest are in the filesystem. + Status s = SyncDirIfManifest(); + if (!s.ok()) { + return s; + } + + if (fdatasync(fd_) < 0) { + s = IOError(filename_, errno); + } + + return s; + } +}; +#endif + static int LockOrUnlock(int fd, bool lock) { errno = 0; struct flock f; @@ -386,7 +504,7 @@ class PosixEnv : public Env { PosixEnv(); virtual ~PosixEnv() { fprintf(stderr, "Destroying Env::Default()\n"); - exit(1); + abort(); } virtual Status NewSequentialFile(const std::string& fname, @@ -408,6 +526,7 @@ class PosixEnv : public Env { int fd = open(fname.c_str(), O_RDONLY); if (fd < 0) { s = IOError(fname, errno); +#if !defined(OS_MACOSX) } else if (mmap_limit_.Acquire()) { uint64_t size; s = GetFileSize(fname, &size); @@ -423,6 +542,7 @@ class PosixEnv : public Env { if (!s.ok()) { mmap_limit_.Release(); } +#endif } else { *result = new PosixRandomAccessFile(fname, fd); } @@ -437,7 +557,11 @@ class PosixEnv : public Env { *result = NULL; s = IOError(fname, errno); } else { +#if defined(OS_MACOSX) + *result = new PosixWriteableFile(fname, fd); +#else *result = new PosixMmapFile(fname, fd, page_size_); +#endif } return s; } @@ -467,7 +591,7 @@ class PosixEnv : public Env { result = IOError(fname, errno); } return result; - }; + } virtual Status CreateDir(const std::string& name) { Status result; @@ -475,7 +599,7 @@ class PosixEnv : public Env { result = IOError(name, errno); } return result; - }; + } virtual Status DeleteDir(const std::string& name) { Status result; @@ -483,7 +607,7 @@ class PosixEnv : public Env { result = IOError(name, errno); } return result; - }; + } virtual Status GetFileSize(const std::string& fname, uint64_t* size) { Status s; @@ -589,7 +713,7 @@ class PosixEnv : public Env { void PthreadCall(const char* label, int result) { if (result != 0) { fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); - exit(1); + abort(); } } diff --git a/src/leveldb/util/hash.cc b/src/leveldb/util/hash.cc index ba181808..07cf0220 100644 --- a/src/leveldb/util/hash.cc +++ b/src/leveldb/util/hash.cc @@ -6,6 +6,13 @@ #include "util/coding.h" #include "util/hash.h" +// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through +// between switch labels. The real definition should be provided externally. +// This one is a fallback version for unsupported compilers. +#ifndef FALLTHROUGH_INTENDED +#define FALLTHROUGH_INTENDED do { } while (0) +#endif + namespace leveldb { uint32_t Hash(const char* data, size_t n, uint32_t seed) { @@ -28,10 +35,10 @@ uint32_t Hash(const char* data, size_t n, uint32_t seed) { switch (limit - data) { case 3: h += data[2] << 16; - // fall through + FALLTHROUGH_INTENDED; case 2: h += data[1] << 8; - // fall through + FALLTHROUGH_INTENDED; case 1: h += data[0]; h *= m; diff --git a/src/leveldb/util/random.h b/src/leveldb/util/random.h index 07538242..ddd51b1c 100644 --- a/src/leveldb/util/random.h +++ b/src/leveldb/util/random.h @@ -16,7 +16,12 @@ class Random { private: uint32_t seed_; public: - explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { } + explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { + // Avoid bad seeds. + if (seed_ == 0 || seed_ == 2147483647L) { + seed_ = 1; + } + } uint32_t Next() { static const uint32_t M = 2147483647L; // 2^31-1 static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 diff --git a/src/main.cpp b/src/main.cpp index 1553d149..d45648a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,8 +61,8 @@ CMedianFilter cPeerBlockCounts(8, 0); // Amount of blocks that other nodes map mapOrphanBlocks; multimap mapOrphanBlocksByPrev; -map mapOrphanTransactions; -map > mapOrphanTransactionsByPrev; +map mapOrphanTransactions; +map > mapOrphanTransactionsByPrev; // Constant stuff for coinbase transactions we create: CScript COINBASE_FLAGS; @@ -70,8 +70,8 @@ CScript COINBASE_FLAGS; const string strMessageMagic = "Datacoin Signed Message:\n"; double dPrimesPerSec = 0.0; -double dChainsPerMinute = 0.0; double dChainsPerDay = 0.0; +double dBlocksPerDay = 0.0; int64 nHPSTimerStart = 0; // Settings @@ -288,16 +288,12 @@ CBlockTreeDB *pblocktree = NULL; // mapOrphanTransactions // -bool AddOrphanTx(const CDataStream& vMsg) +bool AddOrphanTx(const CTransaction& tx) { - CTransaction tx; - CDataStream(vMsg) >> tx; uint256 hash = tx.GetHash(); if (mapOrphanTransactions.count(hash)) return false; - CDataStream* pvMsg = new CDataStream(vMsg); - // Ignore big transactions, to avoid a // send-big-orphans memory exhaustion attack. If a peer has a legitimate // large transaction with a missing parent then we assume @@ -305,16 +301,16 @@ bool AddOrphanTx(const CDataStream& vMsg) // have been mined or received. // 10,000 orphans, each of which is at most 5,000 bytes big is // at most 500 megabytes of orphans: - if (pvMsg->size() > 5000) + unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); + if (sz > 5000) { - printf("ignoring large orphan tx (size: %"PRIszu", hash: %s)\n", pvMsg->size(), hash.ToString().c_str()); - delete pvMsg; + printf("ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString().c_str()); return false; } - mapOrphanTransactions[hash] = pvMsg; + mapOrphanTransactions[hash] = tx; BOOST_FOREACH(const CTxIn& txin, tx.vin) - mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg)); + mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); printf("stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().c_str(), mapOrphanTransactions.size()); @@ -325,16 +321,13 @@ void static EraseOrphanTx(uint256 hash) { if (!mapOrphanTransactions.count(hash)) return; - const CDataStream* pvMsg = mapOrphanTransactions[hash]; - CTransaction tx; - CDataStream(*pvMsg) >> tx; + const CTransaction& tx = mapOrphanTransactions[hash]; BOOST_FOREACH(const CTxIn& txin, tx.vin) { mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash); if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty()) mapOrphanTransactionsByPrev.erase(txin.prevout.hash); } - delete pvMsg; mapOrphanTransactions.erase(hash); } @@ -345,7 +338,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) { // Evict a random orphan: uint256 randomhash = GetRandHash(); - map::iterator it = mapOrphanTransactions.lower_bound(randomhash); + map::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); EraseOrphanTx(it->first); @@ -371,44 +364,58 @@ bool CTxOut::IsDust() const // which has units satoshis-per-kilobyte. // If you'd pay more than 1/3 in fees // to spend something, then we consider it dust. - // A typical txout is 33 bytes big, and will + // A typical txout is 34 bytes big, and will // need a CTxIn of at least 148 bytes to spend, // so dust is a txout less than 54 uBTC - // (5430 satoshis) with default nMinRelayTxFee + // (5460 satoshis) with default nMinRelayTxFee return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < CTransaction::nMinRelayTxFee); } -bool CTransaction::IsStandard() const +bool CTransaction::IsStandard(string& strReason) const { - if (nVersion > CTransaction::CURRENT_VERSION) + if (nVersion > CTransaction::CURRENT_VERSION || nVersion < 1) { + strReason = "version"; return false; + } - if (!IsFinal()) + if (!IsFinal()) { + strReason = "not-final"; return false; + } // Extremely large transactions with lots of inputs can cost the network // almost as much to process as they cost the sender in fees, because // computing signature hashes is O(ninputs*txsize). Limiting transactions // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. unsigned int sz = this->GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); - if (sz >= MAX_STANDARD_TX_SIZE) + if (sz >= MAX_STANDARD_TX_SIZE) { + strReason = "tx-size"; return false; + } BOOST_FOREACH(const CTxIn& txin, vin) { // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG // pay-to-script-hash, which is 3 ~80-byte signatures, 3 // ~65-byte public keys, plus a few script ops. - if (txin.scriptSig.size() > 500) + if (txin.scriptSig.size() > 500) { + strReason = "scriptsig-size"; return false; - if (!txin.scriptSig.IsPushOnly()) + } + if (!txin.scriptSig.IsPushOnly()) { + strReason = "scriptsig-not-pushonly"; return false; + } } BOOST_FOREACH(const CTxOut& txout, vout) { - if (!::IsStandard(txout.scriptPubKey)) + if (!::IsStandard(txout.scriptPubKey)) { + strReason = "scriptpubkey"; return false; - if (txout.IsDust()) + } + if (txout.IsDust()) { + strReason = "dust"; return false; + } } return true; } @@ -606,23 +613,20 @@ int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree, if (fAllowFree) { - if (nBlockSize == 1) - { - // Transactions under 10K are free - // (about 4500 BTC if made of 50 BTC inputs) - if (nBytes < 10000) - nMinFee = 0; - } - else - { - // Free transaction area - if (nNewBlockSize < 27000) - nMinFee = 0; - } - } - - // To limit dust spam, require base fee if any output is less than 0.01 - if (nMinFee < nBaseFee) + // There is a free transaction area in blocks created by most miners, + // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000 + // to be considered to fall into this category. We don't want to encourage sending + // multiple transactions instead of one big transaction to avoid fees. + // * If we are creating a transaction we allow transactions up to 1,000 bytes + // to be considered safe and assume they can likely make it into this section. + if (nBytes < (mode == GMF_SEND ? 1000 : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))) + nMinFee = 0; + } + + // This code can be removed after enough miners have upgraded to version 0.9. + // Until then, be safe when sending and require a fee if any output + // is less than CENT: + if (nMinFee < nBaseFee && mode == GMF_SEND) { BOOST_FOREACH(const CTxOut& txout, vout) if (txout.nValue < CENT) @@ -673,8 +677,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet"); // Rather not work on nonstandard transactions (unless -testnet) - if (!fTestNet && !tx.IsStandard()) - return error("CTxMemPool::accept() : nonstandard transaction type"); + string strNonStd; + if (!fTestNet && !tx.IsStandard(strNonStd)) + return error("CTxMemPool::accept() : nonstandard transaction (%s)", + strNonStd.c_str()); // is it already in the memory pool? uint256 hash = tx.GetHash(); @@ -814,9 +820,6 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn EraseFromWallets(ptxOld->GetHash()); SyncWithWallets(hash, tx, NULL, true); - printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n", - hash.ToString().c_str(), - mapTx.size()); return true; } @@ -849,15 +852,15 @@ bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive) { LOCK(cs); uint256 hash = tx.GetHash(); + if (fRecursive) { + for (unsigned int i = 0; i < tx.vout.size(); i++) { + std::map::iterator it = mapNextTx.find(COutPoint(hash, i)); + if (it != mapNextTx.end()) + remove(*it->second.ptx, true); + } + } if (mapTx.count(hash)) { - if (fRecursive) { - for (unsigned int i = 0; i < tx.vout.size(); i++) { - std::map::iterator it = mapNextTx.find(COutPoint(hash, i)); - if (it != mapNextTx.end()) - remove(*it->second.ptx, true); - } - } BOOST_FOREACH(const CTxIn& txin, tx.vin) mapNextTx.erase(txin.prevout); mapTx.erase(hash); @@ -1448,6 +1451,11 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin CCoins &outs = view.GetCoins(hash); CCoins outsBlock = CCoins(tx, pindex->nHeight); + // The CCoins serialization does not serialize negative numbers. + // No network rules currently depend on the version here, so an inconsistency is harmless + // but it must be corrected before txout nversion ever influences a network rule. + if (outsBlock.nVersion < 0) + outs.nVersion = outsBlock.nVersion; if (outs != outsBlock) fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted"); @@ -1738,7 +1746,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) } // Disconnect shorter branch - vector vResurrect; + list vResurrect; BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { CBlock block; if (!block.ReadFromDisk(pindex)) @@ -1752,9 +1760,9 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) // Queue memory transactions to resurrect. // We only do this for blocks after the last checkpoint (reorganisation before that // point should only happen with -reindex/-loadblock, or a misbehaving peer. - BOOST_FOREACH(const CTransaction& tx, block.vtx) + BOOST_REVERSE_FOREACH(const CTransaction& tx, block.vtx) if (!tx.IsCoinBase() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate()) - vResurrect.push_back(tx); + vResurrect.push_front(tx); } // Connect longer branch @@ -1820,7 +1828,9 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) BOOST_FOREACH(CTransaction& tx, vResurrect) { // ignore validation errors in resurrected transactions CValidationState stateDummy; - tx.AcceptToMemoryPool(stateDummy, true, false); + if (!tx.AcceptToMemoryPool(stateDummy, true, false)) + mempool.remove(tx, true); + } // Delete redundant memory transactions that are in the connected branch @@ -2075,7 +2085,7 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk uniqueTx.insert(GetTxHash(i)); } if (uniqueTx.size() != vtx.size()) - return state.DoS(100, error("CheckBlock() : duplicate transaction")); + return state.DoS(100, error("CheckBlock() : duplicate transaction"), true); unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, vtx) @@ -2142,7 +2152,8 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) { CScript expect = CScript() << nHeight; - if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) + if (vtx[0].vin[0].scriptSig.size() < expect.size() || + !std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); } } @@ -2196,9 +2207,9 @@ CBigNum CBlockIndex::GetBlockWork() const // fractional multiplier = 1 / meeting target rate // = (TransitionRatio * FractionalDiff) / (TransitionRatio - 1 + FractionalDiff) uint64 nFractionalDifficulty = TargetGetFractionalDifficulty(nBits); - CBigNum bnWork = 256; - for (unsigned int nCount = nTargetMinLength; nCount < TargetGetLength(nBits); nCount++) - bnWork *= nWorkTransitionRatio; + unsigned int nWorkExp = 8; + nWorkExp += nWorkTransitionRatioLog * (TargetGetLength(nBits) - nTargetMinLength); + CBigNum bnWork = CBigNum(1) << nWorkExp; bnWork *= ((uint64) nWorkTransitionRatio) * nFractionalDifficulty; bnWork /= (((uint64) nWorkTransitionRatio - 1) * nFractionalDifficultyMin + nFractionalDifficulty); return bnWork; @@ -2714,6 +2725,7 @@ bool LoadBlockIndex() // Primecoin: Generate prime table when starting up GeneratePrimeTable(); + InitPrimeMiner(); // // Load block index from databases @@ -3169,6 +3181,9 @@ void static ProcessGetData(CNode* pfrom) // Track requests for our stuff. Inventory(inv.hash); + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) + break; + } } @@ -3228,8 +3243,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->nVersion = 300; if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; - if (!vRecv.empty()) + if (!vRecv.empty()) { vRecv >> pfrom->strSubVer; + pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); + } if (!vRecv.empty()) vRecv >> pfrom->nStartingHeight; if (!vRecv.empty()) @@ -3304,7 +3321,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->fSuccessfullyConnected = true; - printf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str()); + printf("receive version message: %s: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->cleanSubVer.c_str(), pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str()); cPeerBlockCounts.input(pfrom->nStartingHeight); @@ -3547,54 +3564,49 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CInv inv(MSG_TX, tx.GetHash()); pfrom->AddInventoryKnown(inv); - // Truncate messages to the size of the tx in them - unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); - unsigned int oldSize = vMsg.size(); - if (nSize < oldSize) { - vMsg.resize(nSize); - printf("truncating oversized TX %s (%u -> %u)\n", - tx.GetHash().ToString().c_str(), - oldSize, nSize); - } - bool fMissingInputs = false; CValidationState state; if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs)) { - RelayTransaction(tx, inv.hash, vMsg); + RelayTransaction(tx, inv.hash); mapAlreadyAskedFor.erase(inv); vWorkQueue.push_back(inv.hash); vEraseQueue.push_back(inv.hash); + printf("AcceptToMemoryPool: %s %s : accepted %s (poolsz %"PRIszu")\n", + pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(), + tx.GetHash().ToString().c_str(), + mempool.mapTx.size()); + // Recursively process any orphan transactions that depended on this one for (unsigned int i = 0; i < vWorkQueue.size(); i++) { uint256 hashPrev = vWorkQueue[i]; - for (map::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin(); + for (set::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin(); mi != mapOrphanTransactionsByPrev[hashPrev].end(); ++mi) { - const CDataStream& vMsg = *((*mi).second); - CTransaction tx; - CDataStream(vMsg) >> tx; - CInv inv(MSG_TX, tx.GetHash()); + const uint256& orphanHash = *mi; + const CTransaction& orphanTx = mapOrphanTransactions[orphanHash]; bool fMissingInputs2 = false; - // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get anyone relaying LegitTxX banned) + // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan + // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get + // anyone relaying LegitTxX banned) CValidationState stateDummy; if (tx.AcceptToMemoryPool(stateDummy, true, true, &fMissingInputs2)) { - printf(" accepted orphan tx %s\n", inv.hash.ToString().c_str()); - RelayTransaction(tx, inv.hash, vMsg); - mapAlreadyAskedFor.erase(inv); - vWorkQueue.push_back(inv.hash); - vEraseQueue.push_back(inv.hash); + printf(" accepted orphan tx %s\n", orphanHash.ToString().c_str()); + RelayTransaction(orphanTx, orphanHash); + mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash)); + vWorkQueue.push_back(orphanHash); + vEraseQueue.push_back(orphanHash); } else if (!fMissingInputs2) { // invalid or too-little-fee orphan - vEraseQueue.push_back(inv.hash); - printf(" removed orphan tx %s\n", inv.hash.ToString().c_str()); + vEraseQueue.push_back(orphanHash); + printf(" removed orphan tx %s\n", orphanHash.ToString().c_str()); } } } @@ -3604,16 +3616,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } else if (fMissingInputs) { - AddOrphanTx(vMsg); + AddOrphanTx(tx); // DoS prevention: do not allow mapOrphanTransactions to grow unbounded unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS); if (nEvicted > 0) printf("mapOrphan overflow, removed %u tx\n", nEvicted); } - int nDoS; + int nDoS = 0; if (state.IsInvalid(nDoS)) - pfrom->Misbehaving(nDoS); + { + printf("%s from %s %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(), + pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str()); + if (nDoS > 0) + pfrom->Misbehaving(nDoS); + } } @@ -3629,11 +3646,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->AddInventoryKnown(inv); CValidationState state; - if (ProcessBlock(state, pfrom, &block)) + if (ProcessBlock(state, pfrom, &block) || state.CorruptionPossible()) mapAlreadyAskedFor.erase(inv); - int nDoS; + int nDoS = 0; if (state.IsInvalid(nDoS)) - pfrom->Misbehaving(nDoS); + if (nDoS > 0) + pfrom->Misbehaving(nDoS); + } @@ -3747,6 +3766,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) LOCK(pfrom->cs_filter); delete pfrom->pfilter; pfrom->pfilter = new CBloomFilter(filter); + pfrom->pfilter->UpdateEmptyFull(); } pfrom->fRelayTxes = true; } @@ -3776,7 +3796,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { LOCK(pfrom->cs_filter); delete pfrom->pfilter; - pfrom->pfilter = NULL; + pfrom->pfilter = new CBloomFilter(); pfrom->fRelayTxes = true; } @@ -3815,6 +3835,9 @@ bool ProcessMessages(CNode* pfrom) if (!pfrom->vRecvGetData.empty()) ProcessGetData(pfrom); + // this maintains the order of responses + if (!pfrom->vRecvGetData.empty()) return fOk; + std::deque::iterator it = pfrom->vRecvMsg.begin(); while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) { // Don't bother if send buffer is too full to respond anyway @@ -3905,6 +3928,8 @@ bool ProcessMessages(CNode* pfrom) if (!fRet) printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize); + + break; } // In case the connection got shut down, its receive buffer was wiped @@ -4218,13 +4243,20 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) return NULL; txNew.vout[0].scriptPubKey << pubkey << OP_CHECKSIG; + // Datacoin HP: Optional automatic donations with every block found + if (dDonationPercentage > 0.001) + { + txNew.vout.resize(2); + txNew.vout[1].scriptPubKey.SetDestination(donationAddress.Get()); + } + // Add our coinbase tx as first transaction pblock->vtx.push_back(txNew); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end // Largest block you're willing to create: - unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); + unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); @@ -4234,7 +4266,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay - unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000); + unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); // Minimum block size you want to create; block will be filled with free transactions @@ -4424,7 +4456,19 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) if (fDebug && GetBoolArg("-printmining")) printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); - pblock->vtx[0].vout[0].nValue = GetBlockValue(pblock->nBits, nFees); + int64 nBlockValue = GetBlockValue(pblock->nBits, nFees); + // Datacoin HP: Optional automatic donations with every block found + if (dDonationPercentage > 0.001) + { + int64 nDonationValue = nBlockValue * dDonationPercentage / 100.0; + // Make sure the transaction will be valid + nDonationValue = std::max(nDonationValue, MIN_TXOUT_AMOUNT); + nDonationValue = std::min(nDonationValue, nBlockValue - MIN_TXOUT_AMOUNT); + pblock->vtx[0].vout[0].nValue = nBlockValue - nDonationValue; + pblock->vtx[0].vout[1].nValue = nDonationValue; + } + else + pblock->vtx[0].vout[0].nValue = nBlockValue; pblocktemplate->vTxFees[0] = -nFees; // Fill in header @@ -4447,11 +4491,11 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) } -void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, bool fNoReset) { // Update nExtraNonce static uint256 hashPrevBlock; - if (hashPrevBlock != pblock->hashPrevBlock) + if (!fNoReset && hashPrevBlock != pblock->hashPrevBlock) { nExtraNonce = 0; hashPrevBlock = pblock->hashPrevBlock; @@ -4551,6 +4595,9 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) void static BitcoinMiner(CWallet *pwallet) { + static CCriticalSection cs; + static bool fTimerStarted = false; + bool fPrintStatsAtEnd = false; printf("DatacoinMiner started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("datacoin-miner"); @@ -4560,9 +4607,57 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nExtraNonce = 0; unsigned int nPrimorialMultiplier = nPrimorialHashFactor; - double dTimeExpected = 0; // time expected to prime chain (micro-second) - int64 nSieveGenTime = 0; // how many milliseconds sieve generation took - bool fIncrementPrimorial = true; // increase or decrease primorial factor + int nAdjustPrimorial = 1; // increase or decrease primorial factor + const unsigned int nRoundSamples = 40; // how many rounds to sample before adjusting primorial + double dSumBlockExpected = 0.0; // sum of expected blocks + int64 nSumRoundTime = 0; // sum of round times + unsigned int nRoundNum = 0; // number of rounds + double dAverageBlockExpectedPrev = 0.0; // previous average expected blocks per second + unsigned int nPrimorialMultiplierPrev = nPrimorialMultiplier; // previous primorial factor + + // Primecoin HP: Increase initial primorial + if (fTestNet) + nPrimorialMultiplier = nInitialPrimorialMultiplierTestnet; + else + nPrimorialMultiplier = nInitialPrimorialMultiplier; + + // Primecoin: Check if a fixed primorial was requested + unsigned int nFixedPrimorial = (unsigned int)GetArg("-primorial", 0); + if (nFixedPrimorial > 0) + { + nFixedPrimorial = std::max(nFixedPrimorial, nPrimorialHashFactor); + nPrimorialMultiplier = nFixedPrimorial; + } + + // Primecoin: Allow choosing the mining protocol version + unsigned int nMiningProtocol = (unsigned int)GetArg("-miningprotocol", 1); + + // Primecoin: Allocate data structures for mining + CSieveOfEratosthenes sieve; + CPrimalityTestParams testParams; + + if (!fTimerStarted) + { + LOCK(cs); + if (!fTimerStarted) + { + fTimerStarted = true; + minerTimer.start(); + + // First thread will print the stats + fPrintStatsAtEnd = true; + } + } + + // Many machines may be using the same key if they are sharing the same wallet + // Make extra nonce unique by setting it to a modulo of the high resolution clock's value + const unsigned int nExtraNonceModulo = 10000000; + boost::chrono::high_resolution_clock::time_point time_now = boost::chrono::high_resolution_clock::now(); + boost::chrono::nanoseconds ns_now = boost::chrono::duration_cast(time_now.time_since_epoch()); + nExtraNonce = ns_now.count() % nExtraNonceModulo; + + // Print the chosen extra nonce for debugging + printf("BitcoinMiner() : Setting initial extra nonce to %u\n", nExtraNonce); try { loop { while (vNodes.empty()) @@ -4584,7 +4679,7 @@ void static BitcoinMiner(CWallet *pwallet) if (!pblocktemplate.get()) return; CBlock *pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, true); if (fDebug && GetBoolArg("-printmining")) printf("Running DatacoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), @@ -4595,31 +4690,31 @@ void static BitcoinMiner(CWallet *pwallet) // int64 nStart = GetTime(); bool fNewBlock = true; - unsigned int nTriedMultiplier = 0; // Primecoin: try to find hash divisible by primorial unsigned int nHashFactor = PrimorialFast(nPrimorialHashFactor); - // Based on mustyoshi's patch from https://bitcointalk.org/index.php?topic=251850.msg2689981#msg2689981 - uint256 phash; mpz_class mpzHash; loop { - // Fast loop + pblock->nNonce++; if (pblock->nNonce >= 0xffff0000) break; // Check that the hash meets the minimum - phash = pblock->GetHeaderHash(); - if (phash < hashBlockHeaderLimit) { - pblock->nNonce++; + uint256 phash = pblock->GetHeaderHash(); + if (phash < hashBlockHeaderLimit) continue; - } - // Check that the hash is divisible by the fixed primorial mpz_set_uint256(mpzHash.get_mpz_t(), phash); - if (!mpz_divisible_ui_p(mpzHash.get_mpz_t(), nHashFactor)) { - pblock->nNonce++; - continue; + if (nMiningProtocol >= 2) { + // Primecoin: Mining protocol v0.2 + // Try to find hash that is probable prime + if (!ProbablePrimalityTestWithTrialDivision(mpzHash, 1000, testParams)) + continue; + } else { + // Primecoin: Check that the hash is divisible by the fixed primorial + if (!mpz_divisible_ui_p(mpzHash.get_mpz_t(), nHashFactor)) + continue; } // Use the hash that passed the tests @@ -4629,6 +4724,7 @@ void static BitcoinMiner(CWallet *pwallet) continue; // Primecoin: primorial fixed multiplier mpz_class mpzPrimorial; + mpz_class mpzFixedMultiplier; unsigned int nRoundTests = 0; unsigned int nRoundPrimesHit = 0; int64 nPrimeTimerStart = GetTimeMicros(); @@ -4638,85 +4734,98 @@ void static BitcoinMiner(CWallet *pwallet) { unsigned int nTests = 0; unsigned int nPrimesHit = 0; - unsigned int nChainsHit = 0; + unsigned int vChainsFound[nMaxChainLength]; + for (unsigned int i = 0; i < nMaxChainLength; i++) + vChainsFound[i] = 0; - // Primecoin: adjust round primorial so that the generated prime candidates meet the minimum - mpz_class mpzMultiplierMin = mpzPrimeMin * nHashFactor / mpzHash + 1; - while (mpzPrimorial < mpzMultiplierMin) + // Meter primes/sec + static volatile int64 nPrimeCounter = 0; + static volatile int64 nTestCounter = 0; + static volatile double dChainExpected = 0.0; + static volatile double dBlockExpected = 0.0; + static volatile unsigned int vFoundChainCounter[nMaxChainLength]; + int64 nMillisNow = GetTimeMillis(); + if (nHPSTimerStart == 0) { - if (!PrimeTableGetNextPrime(nPrimorialMultiplier)) - error("DatacoinMiner() : primorial minimum overflow"); - Primorial(nPrimorialMultiplier, mpzPrimorial); + nHPSTimerStart = nMillisNow; + nPrimeCounter = 0; + nTestCounter = 0; + dChainExpected = 0.0; + dBlockExpected = 0.0; + for (unsigned int i = 0; i < nMaxChainLength; i++) + vFoundChainCounter[i] = 0; } - mpz_class mpzFixedMultiplier; - if (mpzPrimorial > nHashFactor) { - mpzFixedMultiplier = mpzPrimorial / nHashFactor; - } else { - mpzFixedMultiplier = 1; + + // Primecoin: Mining protocol v0.2 + if (nMiningProtocol >= 2) + mpzFixedMultiplier = mpzPrimorial; + else + { + if (mpzPrimorial > nHashFactor) + mpzFixedMultiplier = mpzPrimorial / nHashFactor; + else + mpzFixedMultiplier = 1; } // Primecoin: mine for prime chain - unsigned int nProbableChainLength; - if (MineProbablePrimeChain(*pblock, mpzFixedMultiplier, fNewBlock, nTriedMultiplier, nProbableChainLength, nTests, nPrimesHit, nChainsHit, mpzHash, nPrimorialMultiplier, nSieveGenTime, pindexPrev)) + if (MineProbablePrimeChain(*pblock, mpzFixedMultiplier, fNewBlock, nTests, nPrimesHit, mpzHash, pindexPrev, vChainsFound, sieve, testParams)) { SetThreadPriority(THREAD_PRIORITY_NORMAL); + nTotalBlocksFound++; CheckWork(pblock, *pwalletMain, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); - break; } nRoundTests += nTests; nRoundPrimesHit += nPrimesHit; - // Meter primes/sec - static volatile int64 nPrimeCounter; - static volatile int64 nTestCounter; - static volatile int64 nChainCounter; - static double dChainExpected; - int64 nMillisNow = GetTimeMillis(); - if (nHPSTimerStart == 0) +#ifdef USE_GCC_BUILTINS + // Use atomic increment + __sync_add_and_fetch(&nPrimeCounter, nPrimesHit); + __sync_add_and_fetch(&nTestCounter, nTests); + __sync_add_and_fetch(&nTotalTests, nTests); + for (unsigned int i = 0; i < nMaxChainLength; i++) { - nHPSTimerStart = nMillisNow; - nPrimeCounter = 0; - nTestCounter = 0; - nChainCounter = 0; - dChainExpected = 0; + __sync_add_and_fetch(&vTotalChainsFound[i], vChainsFound[i]); + __sync_add_and_fetch(&vFoundChainCounter[i], vChainsFound[i]); } - else - { -#ifdef __GNUC__ - // Use atomic increment - __sync_add_and_fetch(&nPrimeCounter, nPrimesHit); - __sync_add_and_fetch(&nTestCounter, nTests); - __sync_add_and_fetch(&nChainCounter, nChainsHit); #else - nPrimeCounter += nPrimesHit; - nTestCounter += nTests; - nChainCounter += nChainsHit; -#endif + nPrimeCounter += nPrimesHit; + nTestCounter += nTests; + nTotalTests += nTests; + for (unsigned int i = 0; i < nMaxChainLength; i++) + { + vTotalChainsFound[i] += vChainsFound[i]; + vFoundChainCounter[i] += vChainsFound[i]; } +#endif + + nMillisNow = GetTimeMillis(); if (nMillisNow - nHPSTimerStart > 60000) { - static CCriticalSection cs; + LOCK(cs); + nMillisNow = GetTimeMillis(); + if (nMillisNow - nHPSTimerStart > 60000) { - LOCK(cs); - if (nMillisNow - nHPSTimerStart > 60000) + int64 nTimeDiffMillis = nMillisNow - nHPSTimerStart; + nHPSTimerStart = nMillisNow; + double dPrimesPerMinute = 60000.0 * nPrimeCounter / nTimeDiffMillis; + dPrimesPerSec = dPrimesPerMinute / 60.0; + double dTestsPerMinute = 60000.0 * nTestCounter / nTimeDiffMillis; + dChainsPerDay = 86400000.0 * dChainExpected / nTimeDiffMillis; + dBlocksPerDay = 86400000.0 * dBlockExpected / nTimeDiffMillis; + nPrimeCounter = 0; + nTestCounter = 0; + dChainExpected = 0; + dBlockExpected = 0; + static int64 nLogTime = 0; + if (nMillisNow - nLogTime > 59000) { - double dPrimesPerMinute = 60000.0 * nPrimeCounter / (nMillisNow - nHPSTimerStart); - dPrimesPerSec = dPrimesPerMinute / 60.0; - double dTestsPerMinute = 60000.0 * nTestCounter / (nMillisNow - nHPSTimerStart); - dChainsPerMinute = 60000.0 * nChainCounter / (nMillisNow - nHPSTimerStart); - dChainsPerDay = 86400000.0 * dChainExpected / (GetTimeMillis() - nHPSTimerStart); - nHPSTimerStart = nMillisNow; - nPrimeCounter = 0; - nTestCounter = 0; - nChainCounter = 0; - dChainExpected = 0; - static int64 nLogTime = 0; - if (nMillisNow - nLogTime > 59000) - { - nLogTime = nMillisNow; - printf("%s primemeter %9.0f prime/h %9.0f test/h %4.0f %d-chains/h %3.6f chain/d\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nLogTime / 1000).c_str(), dPrimesPerMinute * 60.0, dTestsPerMinute * 60.0, dChainsPerMinute * 60.0, nStatsChainLength, dChainsPerDay); - } + nLogTime = nMillisNow; + if (fLogTimestamps) + printf("primemeter %9.0f prime/h %9.0f test/h %3.8f chain/d %3.8f block/d\n", dPrimesPerMinute * 60.0, dTestsPerMinute * 60.0, dChainsPerDay, dBlocksPerDay); + else + printf("%s primemeter %9.0f prime/h %9.0f test/h %3.8f chain/d %3.8f block/d\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nLogTime / 1000).c_str(), dPrimesPerMinute * 60.0, dTestsPerMinute * 60.0, dChainsPerDay, dBlocksPerDay); + PrintCompactStatistics(vFoundChainCounter); } } } @@ -4735,49 +4844,101 @@ void static BitcoinMiner(CWallet *pwallet) { // Primecoin: a sieve+primality round completes // Primecoin: estimate time to block - const double dTimeExpectedPrev = dTimeExpected; unsigned int nCalcRoundTests = max(1u, nRoundTests); // Make sure the estimated time is very high if only 0 primes were found if (nRoundPrimesHit == 0) nCalcRoundTests *= 1000; int64 nRoundTime = (GetTimeMicros() - nPrimeTimerStart); - dTimeExpected = (double) nRoundTime / nCalcRoundTests; + double dTimeExpected = (double) nRoundTime / nCalcRoundTests; double dRoundChainExpected = (double) nRoundTests; - for (unsigned int n = 0, nTargetLength = TargetGetLength(pblock->nBits); n < nTargetLength; n++) + unsigned int nTargetLength = TargetGetLength(pblock->nBits); + unsigned int nRequestedLength = nTargetLength; + // Override target length if requested + if (nSieveTargetLength > 0) + nRequestedLength = nSieveTargetLength; + // Calculate expected number of chains for requested length + for (unsigned int n = 0; n < nRequestedLength; n++) { - double dPrimeProbability = EstimateCandidatePrimeProbability(nPrimorialMultiplier, n); - dTimeExpected = dTimeExpected / max(0.01, dPrimeProbability); + double dPrimeProbability = EstimateCandidatePrimeProbability(nPrimorialMultiplier, n, nMiningProtocol); + dTimeExpected /= dPrimeProbability; dRoundChainExpected *= dPrimeProbability; } dChainExpected += dRoundChainExpected; + // Calculate expected number of blocks + double dRoundBlockExpected = dRoundChainExpected; + for (unsigned int n = nRequestedLength; n < nTargetLength; n++) + { + double dPrimeProbability = EstimateNormalPrimeProbability(nPrimorialMultiplier, n, nMiningProtocol); + dTimeExpected /= dPrimeProbability; + dRoundBlockExpected *= dPrimeProbability; + } + // Calculate the effect of fractional difficulty + double dFractionalDiff = GetPrimeDifficulty(pblock->nBits) - nTargetLength; + double dExtraPrimeProbability = EstimateNormalPrimeProbability(nPrimorialMultiplier, nTargetLength, nMiningProtocol); + double dDifficultyFactor = ((1.0 - dFractionalDiff) * (1.0 - dExtraPrimeProbability) + dExtraPrimeProbability); + dRoundBlockExpected *= dDifficultyFactor; + dTimeExpected /= dDifficultyFactor; + dBlockExpected += dRoundBlockExpected; + // Calculate the sum of expected blocks and time + dSumBlockExpected += dRoundBlockExpected; + nSumRoundTime += nRoundTime; + nRoundNum++; + if (nRoundNum >= nRoundSamples) + { + // Calculate average expected blocks per time + double dAverageBlockExpected = dSumBlockExpected / ((double) nSumRoundTime / 1000000.0); + // Compare to previous value + if (dAverageBlockExpected > dAverageBlockExpectedPrev) + nAdjustPrimorial = (nPrimorialMultiplier >= nPrimorialMultiplierPrev) ? 1 : -1; + else + nAdjustPrimorial = (nPrimorialMultiplier >= nPrimorialMultiplierPrev) ? -1 : 1; + if (fDebug && GetBoolArg("-printprimorial")) + printf("PrimecoinMiner() : Rounds total: num=%u primorial=%u block/s=%3.12f\n", nRoundNum, nPrimorialMultiplier, dAverageBlockExpected); + // Store the new value and reset + dAverageBlockExpectedPrev = dAverageBlockExpected; + nPrimorialMultiplierPrev = nPrimorialMultiplier; + dSumBlockExpected = 0.0; + nSumRoundTime = 0; + nRoundNum = 0; + } if (fDebug && GetBoolArg("-printmining")) { - double dPrimeProbabilityBegin = EstimateCandidatePrimeProbability(nPrimorialMultiplier, 0); - unsigned int nTargetLength = TargetGetLength(pblock->nBits); - double dPrimeProbabilityEnd = EstimateCandidatePrimeProbability(nPrimorialMultiplier, nTargetLength - 1); - printf("DatacoinMiner() : Round primorial=%u tests=%u primes=%u time=%uus pprob=%1.6f pprob2=%1.6f tochain=%6.3fd expect=%3.9f\n", nPrimorialMultiplier, nRoundTests, nRoundPrimesHit, (unsigned int) nRoundTime, dPrimeProbabilityBegin, dPrimeProbabilityEnd, ((dTimeExpected/1000000.0))/86400.0, dRoundChainExpected); + double dPrimeProbabilityBegin = EstimateCandidatePrimeProbability(nPrimorialMultiplier, 0, nMiningProtocol); + double dPrimeProbabilityEnd = EstimateCandidatePrimeProbability(nPrimorialMultiplier, nTargetLength - 1, nMiningProtocol); + printf("DataMiner() : Round primorial=%u tests=%u primes=%u time=%uus pprob=%1.6f pprob2=%1.6f pprobextra=%1.6f tochain=%6.3fd expect=%3.12f expectblock=%3.12f\n", nPrimorialMultiplier, nRoundTests, nRoundPrimesHit, (unsigned int) nRoundTime, dPrimeProbabilityBegin, dPrimeProbabilityEnd, dExtraPrimeProbability, ((dTimeExpected/1000000.0))/86400.0, dRoundChainExpected, dRoundBlockExpected); + } + // Primecoin: primorial always needs to be incremented if only 0 primes were found + if (nRoundPrimesHit == 0) + nAdjustPrimorial = 1; + + // Primecoin: reset sieve+primality round timer + nPrimeTimerStart = GetTimeMicros(); + nRoundTests = 0; + nRoundPrimesHit = 0; + // Primecoin: update time and nonce pblock->nTime = max(pblock->nTime, (unsigned int) GetAdjustedTime()); - pblock->nNonce++; loop { - // Fast loop + pblock->nNonce++; if (pblock->nNonce >= 0xffff0000) break; // Check that the hash meets the minimum - phash = pblock->GetHeaderHash(); - if (phash < hashBlockHeaderLimit) { - pblock->nNonce++; + uint256 phash = pblock->GetHeaderHash(); + if (phash < hashBlockHeaderLimit) continue; - } - - // Check that the hash is divisible by the fixed primorial mpz_set_uint256(mpzHash.get_mpz_t(), phash); - if (!mpz_divisible_ui_p(mpzHash.get_mpz_t(), nHashFactor)) { - pblock->nNonce++; - continue; + if (nMiningProtocol >= 2) { + // Primecoin: Mining protocol v0.2 + // Try to find hash that is probable prime + if (!ProbablePrimalityTestWithTrialDivision(mpzHash, 1000, testParams)) + continue; + } else { + // Primecoin: Check that the hash is divisible by the fixed primorial + if (!mpz_divisible_ui_p(mpzHash.get_mpz_t(), nHashFactor)) + continue; } // Use the hash that passed the tests @@ -4786,30 +4947,22 @@ void static BitcoinMiner(CWallet *pwallet) if (pblock->nNonce >= 0xffff0000) break; - // Primecoin: reset sieve+primality round timer - nPrimeTimerStart = GetTimeMicros(); - if (dTimeExpected > dTimeExpectedPrev) - fIncrementPrimorial = !fIncrementPrimorial; - - // Primecoin: primorial always needs to be incremented if only 0 primes were found - if (nRoundPrimesHit == 0) - fIncrementPrimorial = true; - - nRoundTests = 0; - nRoundPrimesHit = 0; - // Primecoin: dynamic adjustment of primorial multiplier - if (fIncrementPrimorial) - { - if (!PrimeTableGetNextPrime(nPrimorialMultiplier)) - error("DatacoinMiner() : primorial increment overflow"); - } - else if (nPrimorialMultiplier > nPrimorialHashFactor) - { - if (!PrimeTableGetPreviousPrime(nPrimorialMultiplier)) - error("DatacoinMiner() : primorial decrement overflow"); + if (nFixedPrimorial == 0 && nAdjustPrimorial != 0) { + if (nAdjustPrimorial > 0) + { + if (!PrimeTableGetNextPrime(nPrimorialMultiplier)) + error("DatacoinMiner() : primorial increment overflow"); + } + else if (nPrimorialMultiplier > nPrimorialHashFactor) + { + if (!PrimeTableGetPreviousPrime(nPrimorialMultiplier)) + error("DatacoinMiner() : primorial decrement overflow"); + } + Primorial(nPrimorialMultiplier, mpzPrimorial); + nAdjustPrimorial = 0; + } - Primorial(nPrimorialMultiplier, mpzPrimorial); } } @@ -4817,6 +4970,12 @@ void static BitcoinMiner(CWallet *pwallet) catch (boost::thread_interrupted) { printf("DatacoinMiner terminated\n"); + // Print statistics + if (fPrintStatsAtEnd) + { + PrintMinerStatistics(); + fTimerStarted = false; + } throw; } } @@ -4917,9 +5076,6 @@ class CMainCleanup mapOrphanBlocks.clear(); // orphan transactions - std::map::iterator it3 = mapOrphanTransactions.begin(); - for (; it3 != mapOrphanTransactions.end(); it3++) - delete (*it3).second; mapOrphanTransactions.clear(); } } instance_of_cmaincleanup; diff --git a/src/main.h b/src/main.h index f676d0dc..b364be78 100644 --- a/src/main.h +++ b/src/main.h @@ -29,7 +29,12 @@ struct CBlockIndexWorkComparator; /** The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = (1024 * 1024); /** The maximum size for mined blocks */ +/** Obsolete: maximum size for mined blocks */ static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; +/** Default for -blockmaxsize, maximum size for mined blocks **/ +static const unsigned int DEFAULT_BLOCK_MAX_SIZE = MAX_BLOCK_SIZE; +/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ +static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 30000; /** The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5; /** The maximum allowed number of signature check operations in a block (network rule) */ @@ -91,8 +96,8 @@ extern uint64 nLastBlockTx; extern uint64 nLastBlockSize; extern const std::string strMessageMagic; extern double dPrimesPerSec; -extern double dChainsPerMinute; extern double dChainsPerDay; +extern double dBlocksPerDay; extern int64 nHPSTimerStart; extern int64 nTimeBestReceived; extern CCriticalSection cs_setpwalletRegistered; @@ -165,7 +170,7 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet); /** Generate a new block, without valid proof-of-work */ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey); /** Modify the extranonce in a block */ -void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, bool fNoReset = false); /** Do mining precalculation */ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); /** Check mined block */ @@ -578,7 +583,12 @@ class CTransaction /** Check for standard transaction types @return True if all outputs (scriptPubKeys) use only standard transaction forms */ - bool IsStandard() const; + bool IsStandard(std::string& strReason) const; + bool IsStandard() const + { + std::string strReason; + return IsStandard(strReason); + } /** Check for standard transaction types @param[in] mapInputs Map of previous transactions that have outputs we're spending @@ -1930,13 +1940,15 @@ class CValidationState { MODE_ERROR, // run-time error } mode; int nDoS; + bool corruptionPossible; public: - CValidationState() : mode(MODE_VALID), nDoS(0) {} - bool DoS(int level, bool ret = false) { + CValidationState() : mode(MODE_VALID), nDoS(0), corruptionPossible(false) {} + bool DoS(int level, bool ret = false, bool corruptionIn = false) { if (mode == MODE_ERROR) return ret; nDoS += level; mode = MODE_INVALID; + corruptionPossible = corruptionIn; return ret; } bool Invalid(bool ret = false) { @@ -1966,14 +1978,13 @@ class CValidationState { } return false; } + bool CorruptionPossible() { + return corruptionPossible; + } }; - - - - /** Describes a place in the block chain to another node such that if the * other node doesn't have the same branch, it can find a recent common trunk. * The further back it is, the further before the fork it may be. diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index cce770e7..2fe85d44 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -31,6 +31,7 @@ LIBS= \ -l boost_program_options-mt \ -l boost_thread_win32-mt \ -l boost_chrono-mt \ + -l boost_timer-mt \ -l db_cxx \ -l ssl \ -l crypto \ diff --git a/src/makefile.linux-mingw64 b/src/makefile.linux-mingw64 index db0e3991..39b89a3e 100644 --- a/src/makefile.linux-mingw64 +++ b/src/makefile.linux-mingw64 @@ -31,13 +31,16 @@ LIBS= \ -l boost_program_options-mt \ -l boost_thread_win32-mt \ -l boost_chrono-mt \ + -l boost_timer-mt \ -l db_cxx \ -l ssl \ -l crypto \ -l z \ - -l gmp + -Wl,-Bdynamic \ + -l gmp \ + -Wl,-Bstatic -DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DBOOST_USE_WINDOWS_H -DFD_SETSIZE=1024 -DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x501 +DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DBOOST_USE_WINDOWS_H -DFD_SETSIZE=1024 -DWIN32_LEAN_AND_MEAN -DWINVER=0x500 DEBUGFLAGS=-g xCXXFLAGS=-O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) $(CXXFLAGS) # enable: ASLR, DEP and large address aware diff --git a/src/makefile.mingw b/src/makefile.mingw index 34caa142..09210115 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -40,12 +40,13 @@ LIBS= \ -l boost_program_options$(BOOST_SUFFIX) \ -l boost_thread$(BOOST_SUFFIX) \ -l boost_chrono$(BOOST_SUFFIX) \ + -l boost_timer$(BOOST_SUFFIX) \ -l db_cxx \ -l ssl \ -l crypto \ -l gmp -DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE +DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE DEBUGFLAGS=-g CFLAGS=-mthreads -O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) # enable: ASLR, DEP and large address aware @@ -65,7 +66,7 @@ ifneq (${USE_IPV6}, -) DEFS += -DUSE_IPV6=$(USE_IPV6) endif -LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi +LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi # TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are HEADERS = $(wildcard *.h) diff --git a/src/makefile.osx b/src/makefile.osx index 1db0e23e..7ee5914f 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -38,6 +38,7 @@ LIBS += \ $(DEPSDIR)/lib/libboost_program_options-mt.a \ $(DEPSDIR)/lib/libboost_thread-mt.a \ $(DEPSDIR)/lib/libboost_chrono-mt.a \ + $(DEPSDIR)/lib/libboost_timer-mt.a \ $(DEPSDIR)/lib/libssl.a \ $(DEPSDIR)/lib/libcrypto.a \ -lz @@ -51,6 +52,7 @@ LIBS += \ -lboost_program_options-mt \ -lboost_thread-mt \ -lboost_chrono-mt \ + -lboost_timer-mt \ -lssl \ -lcrypto \ -lgmp \ @@ -64,7 +66,7 @@ ifdef RELEASE # Compile for maximum compatibility and smallest size. # This requires that dependencies are compiled # the same way. -CFLAGS = -mmacosx-version-min=10.5 -arch i386 -O3 +CFLAGS = -mmacosx-version-min=10.6 -arch i386 -O2 else DEBUGFLAGS = -g endif diff --git a/src/makefile.solaris b/src/makefile.solaris index 36232d5e..805d1965 100644 --- a/src/makefile.solaris +++ b/src/makefile.solaris @@ -39,6 +39,8 @@ LIBS += \ -l boost_filesystem$(BOOST_LIB_SUFFIX) \ -l boost_program_options$(BOOST_LIB_SUFFIX) \ -l boost_thread$(BOOST_LIB_SUFFIX) \ + -l boost_chrono$(BOOST_LIB_SUFFIX) \ + -l boost_timer$(BOOST_LIB_SUFFIX) \ -l db_cxx$(BDB_LIB_SUFFIX) \ -l ssl \ -l crypto \ diff --git a/src/makefile.unix b/src/makefile.unix index 359ac3d8..c806c370 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -39,6 +39,8 @@ LIBS += \ -l boost_filesystem$(BOOST_LIB_SUFFIX) \ -l boost_program_options$(BOOST_LIB_SUFFIX) \ -l boost_thread$(BOOST_LIB_SUFFIX) \ + -l boost_chrono$(BOOST_LIB_SUFFIX) \ + -l boost_timer$(BOOST_LIB_SUFFIX) \ -l db_cxx$(BDB_LIB_SUFFIX) \ -l ssl \ -l crypto \ diff --git a/src/net.cpp b/src/net.cpp index 569da7c0..72905915 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -613,7 +613,7 @@ void CNode::copyStats(CNodeStats &stats) X(nTimeConnected); X(addrName); X(nVersion); - X(strSubVer); + X(cleanSubVer); X(fInbound); X(nStartingHeight); X(nMisbehavior); @@ -1565,6 +1565,9 @@ void ThreadMessageHandler() CNode* pnodeTrickle = NULL; if (!vNodesCopy.empty()) pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())]; + + bool fSleep = true; + BOOST_FOREACH(CNode* pnode, vNodesCopy) { if (pnode->fDisconnect) @@ -1574,8 +1577,18 @@ void ThreadMessageHandler() { TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); if (lockRecv) + { if (!ProcessMessages(pnode)) pnode->CloseSocketDisconnect(); + + if (pnode->nSendSize < SendBufferSize()) + { + if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg[0].complete())) + { + fSleep = false; + } + } + } } boost::this_thread::interruption_point(); @@ -1593,8 +1606,8 @@ void ThreadMessageHandler() BOOST_FOREACH(CNode* pnode, vNodesCopy) pnode->Release(); } - - MilliSleep(100); + if (fSleep) + MilliSleep(100); } } diff --git a/src/net.h b/src/net.h index 4c1ccf81..2b5a9c2b 100644 --- a/src/net.h +++ b/src/net.h @@ -98,7 +98,7 @@ class CNodeStats int64 nTimeConnected; std::string addrName; int nVersion; - std::string strSubVer; + std::string cleanSubVer; bool fInbound; int nStartingHeight; int nMisbehavior; @@ -177,7 +177,11 @@ class CNode std::string addrName; CService addrLocal; int nVersion; - std::string strSubVer; + // strSubVer is whatever byte array we read from the wire. However, this field is intended + // to be printed out, displayed to humans in various forms and so on. So we sanitize it and + // store the sanitized version in cleanSubVer. The original should be used when dealing with + // the network or wire types and the cleaned string used when displayed or logged. + std::string strSubVer, cleanSubVer; bool fOneShot; bool fClient; bool fInbound; @@ -255,7 +259,7 @@ class CNode hashCheckpointKnown = 0; fRelayTxes = false; setInventoryKnown.max_size(SendBufferSize() / 1000); - pfilter = NULL; + pfilter = new CBloomFilter(); // Be shy and don't send version until we hear if (hSocket != INVALID_SOCKET && !fInbound) diff --git a/src/netbase.cpp b/src/netbase.cpp index 57b356eb..a3df7cff 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -856,7 +856,7 @@ std::vector CNetAddr::GetGroup() const nBits = 4; } // for he.net, use /36 groups - else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70) + else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70) nBits = 36; // for the rest of the IPv6 network, use /32 groups else diff --git a/src/prime.cpp b/src/prime.cpp index 76446924..62463034 100644 --- a/src/prime.cpp +++ b/src/prime.cpp @@ -12,8 +12,9 @@ // Prime Table std::vector vPrimes; unsigned int nSieveSize = nDefaultSieveSize; -unsigned int nSievePercentage = nDefaultSievePercentage; +unsigned int nSieveFilterPrimes = nDefaultSieveFilterPrimes; unsigned int nSieveExtensions = nDefaultSieveExtensions; +unsigned int nL1CacheSize = nDefaultL1CacheSize; static unsigned int int_invert(unsigned int a, unsigned int nPrime); @@ -22,12 +23,16 @@ void GeneratePrimeTable() const unsigned int nDefaultSieveExt = (fTestNet) ? nDefaultSieveExtensionsTestnet : nDefaultSieveExtensions; nSieveExtensions = (unsigned int)GetArg("-sieveextensions", nDefaultSieveExt); nSieveExtensions = std::max(std::min(nSieveExtensions, nMaxSieveExtensions), nMinSieveExtensions); - nSievePercentage = (unsigned int)GetArg("-sievepercentage", nDefaultSievePercentage); - nSievePercentage = std::max(std::min(nSievePercentage, nMaxSievePercentage), nMinSievePercentage); nSieveSize = (unsigned int)GetArg("-sievesize", nDefaultSieveSize); nSieveSize = std::max(std::min(nSieveSize, nMaxSieveSize), nMinSieveSize); - printf("GeneratePrimeTable() : setting nSieveExtensions = %u, nSievePercentage = %u, nSieveSize = %u\n", nSieveExtensions, nSievePercentage, nSieveSize); - const unsigned nPrimeTableLimit = nSieveSize; + nSieveFilterPrimes = (unsigned int)GetArg("-sievefilterprimes", nDefaultSieveFilterPrimes); + nSieveFilterPrimes = std::max(std::min(nSieveFilterPrimes, nMaxSieveFilterPrimes), nMinSieveFilterPrimes); + nL1CacheSize = (unsigned int)GetArg("-l1cachesize", nDefaultL1CacheSize); + nL1CacheSize = std::max(std::min(nL1CacheSize, nMaxL1CacheSize), nMinL1CacheSize); + nL1CacheSize = nL1CacheSize / (nRequiredAlignment / 8) * (nRequiredAlignment / 8); + printf("GeneratePrimeTable() : setting nSieveExtensions = %u, nSieveSize = %u, nSieveFilterPrimes = %u, nL1CacheSize = %u\n", nSieveExtensions, nSieveSize, nSieveFilterPrimes, nL1CacheSize); + + const unsigned nPrimeTableLimit = 1000000u; vPrimes.clear(); // Generate prime table using sieve of Eratosthenes std::vector vfComposite (nPrimeTableLimit, false); @@ -44,6 +49,109 @@ void GeneratePrimeTable() printf("GeneratePrimeTable() : prime table [1, %u] generated with %u primes\n", nPrimeTableLimit, (unsigned int) vPrimes.size()); } +// Mining statistics +uint64 nTotalTests; +unsigned int nTotalBlocksFound; +std::vector vTotalChainsFound; +boost::timer::cpu_timer minerTimer; +int nSieveTargetLength = -1; + +// Datacoin HP: Optional automatic donations with every block found +CBitcoinAddress donationAddress; +double dDonationPercentage; + +void ResetMinerStatistics() +{ + nTotalTests = 0; + nTotalBlocksFound = 0; + vTotalChainsFound = std::vector (nMaxChainLength, 0); +} + +void InitPrimeMiner() +{ + ResetMinerStatistics(); + nSieveTargetLength = std::min((int)GetArg("-sievetargetlength", nDefaultSieveTargetLength), (int)nMaxChainLength); + if (nSieveTargetLength > 0) + printf("InitPrimeMiner() : Setting sieve target length to %d\n", nSieveTargetLength); + + // Datacoin HP: Optional automatic donations with every block found + std::string strDonationPercentage = GetArg("-donationpercentage", strDefaultDonationPercentage); + std::string strDonationAddress = GetArg("-donationaddress", !fTestNet ? strDefaultDonationAddress : strDefaultDonationAddressTestnet); + dDonationPercentage = atof(strDonationPercentage.c_str()); + if (dDonationPercentage < dMinDonationPercentage) + dDonationPercentage = 0.0; + dDonationPercentage = std::min(dDonationPercentage, dMaxDonationPercentage); + donationAddress = CBitcoinAddress(strDonationAddress); + if (!donationAddress.IsValid()) + { + dDonationPercentage = 0.0; + printf("InitPrimeMiner(): Donation address is invalid, disabling donations\n"); + } + if (dDonationPercentage > 0.001) + printf("InitPrimeMiner(): Donating %2.2f%% of every block found to %s (thank you!)\n", dDonationPercentage, strDonationAddress.c_str()); + else + printf("InitPrimeMiner(): Donations disabled\n"); +} + +void PrintMinerStatistics() +{ + printf("========================================================================\n"); + printf("Miner statistics\n"); + printf("========================================================================\n"); + + boost::timer::cpu_times const elapsed_times(minerTimer.elapsed()); + int64 nRunningTime = elapsed_times.wall; + double dRunningHours = (double)nRunningTime / 3600000000000.0; + int64 nCPUTime = elapsed_times.system + elapsed_times.user; + double dCPUHours = (double)nCPUTime / 3600000000000.0; + printf("Running time: %.4f hours\n", dRunningHours); + printf("CPU time: %.4f hours\n", dCPUHours); + + printf("Tests: %"PRI64u"\n", nTotalTests); + printf("Blocks found: %u\n", nTotalBlocksFound); + + // Find the last non-zero chain count + unsigned int nMaxPrintLength = nMaxChainLength; + for (int i = nMaxChainLength - 1; i >= 0; i--) + { + if (vTotalChainsFound[i] > 0) + { + nMaxPrintLength = i + 1; + break; + } + } + + printf("\n"); + printf("Chain statistics\n"); + for (unsigned int i = 0; i < nMaxPrintLength; i++) + printf("%u-chains: %"PRI64u"\n", i + 1, vTotalChainsFound[i]); + + printf("========================================================================\n"); + + // Reset statistics + nHPSTimerStart = 0; + ResetMinerStatistics(); +} + +void PrintCompactStatistics(volatile unsigned int vFoundChainCounter[nMaxChainLength]) +{ + std::string strOutput; + if (fLogTimestamps) + strOutput = "chainstats "; + else + strOutput = strprintf("%s chainstats ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); + for (unsigned int i = 0; i < nMaxChainLength; i++) + { + if (vFoundChainCounter[i]) + strOutput += strprintf(" %uch: %u", i + 1, vFoundChainCounter[i]); + } + printf("%s\n", strOutput.c_str()); + + // Reset the statistics + for (unsigned int i = 0; i < nMaxChainLength; i++) + vFoundChainCounter[i] = 0; +} + // Get next prime number of p bool PrimeTableGetNextPrime(unsigned int& p) { @@ -510,66 +618,40 @@ unsigned int EstimateWorkTransition(unsigned int nPrevWorkTransition, unsigned i /* PRIMECOIN MINING */ /********************/ -class CPrimalityTestParams -{ -public: - // GMP variables - mpz_t mpzE; - mpz_t mpzR; - mpz_t mpzRplusOne; - - // GMP C++ variables - mpz_class mpzOriginMinusOne; - mpz_class mpzOriginPlusOne; - mpz_class N; - - // Values specific to a round - unsigned int nBits; - unsigned int nPrimorialSeq; - unsigned int nCandidateType; - - // Results - unsigned int nChainLength; - - CPrimalityTestParams(unsigned int nBits, unsigned int nPrimorialSeq) - { - this->nBits = nBits; - this->nPrimorialSeq = nPrimorialSeq; - nChainLength = 0; - mpz_init(mpzE); - mpz_init(mpzR); - mpz_init(mpzRplusOne); - } - - ~CPrimalityTestParams() - { - mpz_clear(mpzE); - mpz_clear(mpzR); - mpz_clear(mpzRplusOne); - } -}; - // Check Fermat probable primality test (2-PRP): 2 ** (n-1) = 1 (mod n) // true: n is probable prime // false: n is composite; set fractional length in the nLength output static bool FermatProbablePrimalityTestFast(const mpz_class& n, unsigned int& nLength, CPrimalityTestParams& testParams, bool fFastFail = false) { - // Faster GMP version - mpz_t& mpzE = testParams.mpzE; - mpz_t& mpzR = testParams.mpzR; - - mpz_sub_ui(mpzE, n.get_mpz_t(), 1); - mpz_powm(mpzR, mpzTwo.get_mpz_t(), mpzE, n.get_mpz_t()); - if (mpz_cmp_ui(mpzR, 1) == 0) + mpz_class& mpzNMinusOne = testParams.mpzNMinusOne; + mpz_class& mpzE = testParams.mpzE; + mpz_class& mpzBase = testParams.mpzBase; + mpz_class& mpzR = testParams.mpzR; + mpz_class& mpzR2 = testParams.mpzR2; + mpz_class& mpzFrac = testParams.mpzFrac; + + mpzNMinusOne = n - 1; + unsigned int nTrailingZeros = mpz_scan1(mpzNMinusOne.get_mpz_t(), 0); + if (unlikely(nTrailingZeros > 9)) + nTrailingZeros = 9; + // Euler's criterion: 2 ** ((n-1)/2) needs to be either -1 or 1 (mod n) + mpz_tdiv_q_2exp(mpzE.get_mpz_t(), mpzNMinusOne.get_mpz_t(), nTrailingZeros); + unsigned int nShiftCount = (1U << (nTrailingZeros - 1)) - 1; + mpzBase = mpzTwo << nShiftCount; + mpz_powm(mpzR.get_mpz_t(), mpzBase.get_mpz_t(), mpzE.get_mpz_t(), n.get_mpz_t()); + if (unlikely(mpzR == 1 || mpzR == mpzNMinusOne)) return true; - if (fFastFail) + if (likely(fFastFail)) return false; - // Failed Fermat test, calculate fractional length - mpz_sub(mpzE, n.get_mpz_t(), mpzR); - mpz_mul_2exp(mpzR, mpzE, nFractionalBits); - mpz_tdiv_q(mpzE, mpzR, n.get_mpz_t()); - unsigned int nFractionalLength = mpz_get_ui(mpzE); - if (nFractionalLength >= (1 << nFractionalBits)) + // Failed test, calculate fractional length + mpzR2 = mpzR * mpzR; + mpzR = mpzR2 % n; // derive Fermat test remainder + + mpzFrac = n - mpzR; + mpzFrac <<= nFractionalBits; + mpzFrac /= n; + unsigned int nFractionalLength = mpzFrac.get_ui(); + if (unlikely(nFractionalLength >= (1 << nFractionalBits))) return error("FermatProbablePrimalityTest() : fractional assert"); nLength = (nLength & TARGET_LENGTH_MASK) | nFractionalLength; return false; @@ -582,50 +664,51 @@ static bool FermatProbablePrimalityTestFast(const mpz_class& n, unsigned int& nL // Return values // true: n is probable prime // false: n is composite; set fractional length in the nLength output -static bool EulerLagrangeLifchitzPrimalityTestFast(const mpz_class& n, bool fSophieGermain, unsigned int& nLength, CPrimalityTestParams& testParams) +static bool EulerLagrangeLifchitzPrimalityTestFast(const mpz_class& n, bool fSophieGermain, unsigned int& nLength, CPrimalityTestParams& testParams, bool fFastFail = false) { - // Faster GMP version - mpz_t& mpzE = testParams.mpzE; - mpz_t& mpzR = testParams.mpzR; - mpz_t& mpzRplusOne = testParams.mpzRplusOne; - - mpz_sub_ui(mpzE, n.get_mpz_t(), 1); - mpz_tdiv_q_2exp(mpzE, mpzE, 1); - mpz_powm(mpzR, mpzTwo.get_mpz_t(), mpzE, n.get_mpz_t()); - unsigned int nMod8 = mpz_get_ui(n.get_mpz_t()) % 8; + mpz_class& mpzNMinusOne = testParams.mpzNMinusOne; + mpz_class& mpzE = testParams.mpzE; + mpz_class& mpzBase = testParams.mpzBase; + mpz_class& mpzR = testParams.mpzR; + mpz_class& mpzR2 = testParams.mpzR2; + mpz_class& mpzFrac = testParams.mpzFrac; + + mpzNMinusOne = n - 1; + unsigned int nTrailingZeros = mpz_scan1(mpzNMinusOne.get_mpz_t(), 0); + if (unlikely(nTrailingZeros > 9)) + nTrailingZeros = 9; + mpz_tdiv_q_2exp(mpzE.get_mpz_t(), mpzNMinusOne.get_mpz_t(), nTrailingZeros); + unsigned int nShiftCount = (1U << (nTrailingZeros - 1)) - 1; + mpzBase = mpzTwo << nShiftCount; + mpz_powm(mpzR.get_mpz_t(), mpzBase.get_mpz_t(), mpzE.get_mpz_t(), n.get_mpz_t()); + unsigned int nMod8 = n.get_ui() % 8; bool fPassedTest = false; - if (fSophieGermain && (nMod8 == 7)) // Euler & Lagrange - fPassedTest = !mpz_cmp_ui(mpzR, 1); - else if (fSophieGermain && (nMod8 == 3)) // Lifchitz - { - mpz_add_ui(mpzRplusOne, mpzR, 1); - fPassedTest = !mpz_cmp(mpzRplusOne, n.get_mpz_t()); - } - else if ((!fSophieGermain) && (nMod8 == 5)) // Lifchitz - { - mpz_add_ui(mpzRplusOne, mpzR, 1); - fPassedTest = !mpz_cmp(mpzRplusOne, n.get_mpz_t()); - } - else if ((!fSophieGermain) && (nMod8 == 1)) // LifChitz - fPassedTest = !mpz_cmp_ui(mpzR, 1); + if (fSophieGermain && nMod8 == 7) // Euler & Lagrange + fPassedTest = (mpzR == 1); + else if (fSophieGermain && nMod8 == 3) // Lifchitz + fPassedTest = (mpzR == mpzNMinusOne); + else if (!fSophieGermain && nMod8 == 5) // Lifchitz + fPassedTest = (mpzR == mpzNMinusOne); + else if (!fSophieGermain && nMod8 == 1) // LifChitz + fPassedTest = (mpzR == 1); else return error("EulerLagrangeLifchitzPrimalityTest() : invalid n %% 8 = %d, %s", nMod8, (fSophieGermain? "first kind" : "second kind")); - - if (fPassedTest) - { + + if (unlikely(fPassedTest)) return true; - } - + if (likely(fFastFail)) + return false; + // Failed test, calculate fractional length - mpz_mul(mpzE, mpzR, mpzR); - mpz_tdiv_r(mpzR, mpzE, n.get_mpz_t()); // derive Fermat test remainder + mpzR2 = mpzR * mpzR; + mpzR = mpzR2 % n; // derive Fermat test remainder - mpz_sub(mpzE, n.get_mpz_t(), mpzR); - mpz_mul_2exp(mpzR, mpzE, nFractionalBits); - mpz_tdiv_q(mpzE, mpzR, n.get_mpz_t()); - unsigned int nFractionalLength = mpz_get_ui(mpzE); - - if (nFractionalLength >= (1 << nFractionalBits)) + mpzFrac = n - mpzR; + mpzFrac <<= nFractionalBits; + mpzFrac /= n; + unsigned int nFractionalLength = mpzFrac.get_ui(); + + if (unlikely(nFractionalLength >= (1 << nFractionalBits))) return error("EulerLagrangeLifchitzPrimalityTest() : fractional assert"); nLength = (nLength & TARGET_LENGTH_MASK) | nFractionalLength; return false; @@ -635,38 +718,65 @@ static bool EulerLagrangeLifchitzPrimalityTestFast(const mpz_class& n, bool fSop // fSophieGermain: // true - Test for Cunningham Chain of first kind (n, 2n+1, 4n+3, ...) // false - Test for Cunningham Chain of second kind (n, 2n-1, 4n-3, ...) -// Return value: -// true - Probable Cunningham Chain found (length at least 2) -// false - Not Cunningham Chain -static bool ProbableCunninghamChainTestFast(const mpz_class& n, bool fSophieGermain, bool fFermatTest, unsigned int& nProbableChainLength, CPrimalityTestParams& testParams) +static void ProbableCunninghamChainTestFast(const mpz_class& n, bool fSophieGermain, unsigned int& nProbableChainLength, CPrimalityTestParams& testParams) { nProbableChainLength = 0; // Fermat test for n first if (!FermatProbablePrimalityTestFast(n, nProbableChainLength, testParams, true)) - return false; + return; // Euler-Lagrange-Lifchitz test for the following numbers in chain - mpz_class &N = testParams.N; + mpz_class &N = testParams.mpzN; N = n; - while (true) + for (unsigned int nChainSeq = 1; true; nChainSeq++) { TargetIncrementLength(nProbableChainLength); N <<= 1; N += (fSophieGermain? 1 : (-1)); - if (fFermatTest) - { - if (!FermatProbablePrimalityTestFast(N, nProbableChainLength, testParams)) - break; - } - else - { - if (!EulerLagrangeLifchitzPrimalityTestFast(N, fSophieGermain, nProbableChainLength, testParams)) - break; - } + bool fFastFail = nChainSeq < 4; + if (!EulerLagrangeLifchitzPrimalityTestFast(N, fSophieGermain, nProbableChainLength, testParams, fFastFail)) + break; } +} - return (TargetGetLength(nProbableChainLength) >= 2); +// Test Probable BiTwin Chain for: mpzOrigin +// Test the numbers in the optimal order for any given chain length +// Gives the correct length of a BiTwin chain even for short chains +static void ProbableBiTwinChainTestFast(const mpz_class& mpzOrigin, unsigned int& nProbableChainLength, CPrimalityTestParams& testParams) +{ + mpz_class& mpzOriginMinusOne = testParams.mpzOriginMinusOne; + mpz_class& mpzOriginPlusOne = testParams.mpzOriginPlusOne; + nProbableChainLength = 0; + + // Fermat test for origin-1 first + mpzOriginMinusOne = mpzOrigin - 1; + if (!FermatProbablePrimalityTestFast(mpzOriginMinusOne, nProbableChainLength, testParams, true)) + return; + TargetIncrementLength(nProbableChainLength); + + // Fermat test for origin+1 + mpzOriginPlusOne = mpzOrigin + 1; + if (!FermatProbablePrimalityTestFast(mpzOriginPlusOne, nProbableChainLength, testParams, true)) + return; + TargetIncrementLength(nProbableChainLength); + + // Euler-Lagrange-Lifchitz test for the following numbers in chain + for (unsigned int nChainSeq = 2; true; nChainSeq += 2) + { + mpzOriginMinusOne <<= 1; + mpzOriginMinusOne++; + bool fFastFail = nChainSeq < 4; + if (!EulerLagrangeLifchitzPrimalityTestFast(mpzOriginMinusOne, true, nProbableChainLength, testParams, fFastFail)) + break; + TargetIncrementLength(nProbableChainLength); + + mpzOriginPlusOne <<= 1; + mpzOriginPlusOne--; + if (!EulerLagrangeLifchitzPrimalityTestFast(mpzOriginPlusOne, false, nProbableChainLength, testParams, fFastFail)) + break; + TargetIncrementLength(nProbableChainLength); + } } // Test probable prime chain for: nOrigin @@ -677,114 +787,182 @@ static bool ProbablePrimeChainTestFast(const mpz_class& mpzPrimeChainOrigin, CPr { const unsigned int nBits = testParams.nBits; const unsigned int nCandidateType = testParams.nCandidateType; - unsigned int& nChainLength = testParams.nChainLength; mpz_class& mpzOriginMinusOne = testParams.mpzOriginMinusOne; mpz_class& mpzOriginPlusOne = testParams.mpzOriginPlusOne; + unsigned int& nChainLength = testParams.nChainLength; nChainLength = 0; // Test for Cunningham Chain of first kind if (nCandidateType == PRIME_CHAIN_CUNNINGHAM1) { mpzOriginMinusOne = mpzPrimeChainOrigin - 1; - ProbableCunninghamChainTestFast(mpzOriginMinusOne, true, false, nChainLength, testParams); + ProbableCunninghamChainTestFast(mpzOriginMinusOne, true, nChainLength, testParams); } else if (nCandidateType == PRIME_CHAIN_CUNNINGHAM2) { // Test for Cunningham Chain of second kind mpzOriginPlusOne = mpzPrimeChainOrigin + 1; - ProbableCunninghamChainTestFast(mpzOriginPlusOne, false, false, nChainLength, testParams); + ProbableCunninghamChainTestFast(mpzOriginPlusOne, false, nChainLength, testParams); } - else + else if (nCandidateType == PRIME_CHAIN_BI_TWIN) { - unsigned int nChainLengthCunningham1 = 0; - unsigned int nChainLengthCunningham2 = 0; - mpzOriginMinusOne = mpzPrimeChainOrigin - 1; - if (ProbableCunninghamChainTestFast(mpzOriginMinusOne, true, false, nChainLengthCunningham1, testParams)) - { - mpzOriginPlusOne = mpzPrimeChainOrigin + 1; - ProbableCunninghamChainTestFast(mpzOriginPlusOne, false, false, nChainLengthCunningham2, testParams); - // Figure out BiTwin Chain length - // BiTwin Chain allows a single prime at the end for odd length chain - nChainLength = - (TargetGetLength(nChainLengthCunningham1) > TargetGetLength(nChainLengthCunningham2))? - (nChainLengthCunningham2 + TargetFromInt(TargetGetLength(nChainLengthCunningham2)+1)) : - (nChainLengthCunningham1 + TargetFromInt(TargetGetLength(nChainLengthCunningham1))); - } + ProbableBiTwinChainTestFast(mpzPrimeChainOrigin, nChainLength, testParams); } return (nChainLength >= nBits); } -// Sieve for mining -boost::thread_specific_ptr psieve; +// Perform Fermat test with trial division +// Return values: +// true - passes trial division test and Fermat test; probable prime +// false - failed either trial division or Fermat test; composite +bool ProbablePrimalityTestWithTrialDivision(const mpz_class& mpzCandidate, unsigned int nTrialDivisionLimit, CPrimalityTestParams& testParams) +{ + unsigned int nDivisor = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23; + unsigned int nDivisorPrimes = 9; + + // Fast trial division for the first few primes + unsigned long nModulo = mpz_tdiv_ui(mpzCandidate.get_mpz_t(), nDivisor); + for (unsigned int i = 0; i < nDivisorPrimes; i++) + { + if (nModulo % vPrimes[i] == 0) + return false; + } + + // Trial division + for (unsigned int i = nDivisorPrimes; i < nTrialDivisionLimit; i++) + { + if (mpz_divisible_ui_p(mpzCandidate.get_mpz_t(), vPrimes[i])) + return false; + } + unsigned int nLength = 0; + return (FermatProbablePrimalityTestFast(mpzCandidate, nLength, testParams, true)); +} + +static void SieveDebugChecks(unsigned int nBits, unsigned int nTriedMultiplier, unsigned int nCandidateType, mpz_class& mpzHash, mpz_class& mpzFixedMultiplier, mpz_class& mpzChainOrigin) +{ + // Debugging code to verify the sieve output + const unsigned int nTargetLength = TargetGetLength(nBits); + mpz_class mpzChainN; + mpz_class mpzChainNMod; + if (nCandidateType == PRIME_CHAIN_CUNNINGHAM1 || nCandidateType == PRIME_CHAIN_BI_TWIN) + { + unsigned int nCC1Length = nTargetLength; + if (nCandidateType == PRIME_CHAIN_BI_TWIN) + nCC1Length = (nTargetLength + 1) / 2; + for (unsigned int nChainPosition = 0; nChainPosition < nCC1Length; nChainPosition++) + { + mpzChainN = mpzChainOrigin << nChainPosition; + mpzChainN--; + for (unsigned int nPrimeSeq = 0; nPrimeSeq < nSieveFilterPrimes; nPrimeSeq++) + { + if (mpz_divisible_ui_p(mpzChainN.get_mpz_t(), vPrimes[nPrimeSeq]) > 0) + { + std::string strHash = mpzHash.get_str(); + std::string strFixedMultiplier = mpzFixedMultiplier.get_str(); + printf("SIEVE BUG: %s * %s * %u * 2^%u - 1 is divisible by %u!\n", strHash.c_str(), strFixedMultiplier.c_str(), nTriedMultiplier, nChainPosition, vPrimes[nPrimeSeq]); + } + } + } + } + if (nCandidateType == PRIME_CHAIN_CUNNINGHAM2 || nCandidateType == PRIME_CHAIN_BI_TWIN) + { + unsigned int nCC2Length = nTargetLength; + if (nCandidateType == PRIME_CHAIN_BI_TWIN) + nCC2Length = nTargetLength / 2; + for (unsigned int nChainPosition = 0; nChainPosition < nCC2Length; nChainPosition++) + { + mpzChainN = mpzChainOrigin << nChainPosition; + mpzChainN++; + for (unsigned int nPrimeSeq = 0; nPrimeSeq < nSieveFilterPrimes; nPrimeSeq++) + { + if (mpz_divisible_ui_p(mpzChainN.get_mpz_t(), vPrimes[nPrimeSeq]) > 0) + { + std::string strHash = mpzHash.get_str(); + std::string strFixedMultiplier = mpzFixedMultiplier.get_str(); + printf("SIEVE BUG: %s * %s * %u * 2^%u + 1 is divisible by %u!\n", strHash.c_str(), strFixedMultiplier.c_str(), nTriedMultiplier, nChainPosition, vPrimes[nPrimeSeq]); + } + } + } + } + if (nCandidateType == 0) + { + std::string strHash = mpzHash.get_str(); + std::string strFixedMultiplier = mpzFixedMultiplier.get_str(); + printf("SIEVE BUG: %s * %s * %u has unknown type!\n", strHash.c_str(), strFixedMultiplier.c_str(), nTriedMultiplier); + } +} // Mine probable prime chain of form: n = h * p# +/- 1 -bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool& fNewBlock, unsigned int& nTriedMultiplier, unsigned int& nProbableChainLength, unsigned int& nTests, unsigned int& nPrimesHit, unsigned int& nChainsHit, mpz_class& mpzHash, unsigned int nPrimorialMultiplier, int64& nSieveGenTime, CBlockIndex* pindexPrev) +bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool& fNewBlock, unsigned int& nTests, unsigned int& nPrimesHit, mpz_class& mpzHash, CBlockIndex* pindexPrev, unsigned int vChainsFound[nMaxChainLength], CSieveOfEratosthenes& sieve, CPrimalityTestParams& testParams) { - CSieveOfEratosthenes *lpsieve; - nProbableChainLength = 0; nTests = 0; nPrimesHit = 0; - nChainsHit = 0; - const unsigned int nBits = block.nBits; - if (fNewBlock && psieve.get() != NULL) + // References to test parameters + unsigned int& nBits = testParams.nBits; + unsigned int& nChainLength = testParams.nChainLength; + unsigned int& nCandidateType = testParams.nCandidateType; + mpz_class& mpzHashFixedMult = testParams.mpzHashFixedMult; + mpz_class& mpzChainOrigin = testParams.mpzChainOrigin; + nBits = block.nBits; + + if (fNewBlock) { // Must rebuild the sieve - psieve.reset(); + sieve.Deplete(); } fNewBlock = false; - int64 nStart; // microsecond timer - if ((lpsieve = psieve.get()) == NULL) + int64 nStart = 0; // microsecond timer + if (!sieve.IsReady() || sieve.IsDepleted()) { // Build sieve - nStart = GetTimeMicros(); - lpsieve = new CSieveOfEratosthenes(nSieveSize, nSievePercentage, nSieveExtensions, nBits, mpzHash, mpzFixedMultiplier, pindexPrev); - while (lpsieve->Weave() && pindexPrev == pindexBest); - nSieveGenTime = GetTimeMicros() - nStart; if (fDebug && GetBoolArg("-printmining")) - printf("MineProbablePrimeChain() : new sieve (%u/%u@%u%%) ready in %uus\n", lpsieve->GetCandidateCount(), nSieveSize, lpsieve->GetProgressPercentage(), (unsigned int) nSieveGenTime); - psieve.reset(lpsieve); + nStart = GetTimeMicros(); + sieve.Reset(nSieveSize, nSieveFilterPrimes, nSieveExtensions, nL1CacheSize, nBits, mpzHash, mpzFixedMultiplier, pindexPrev); + sieve.Weave(); + if (fDebug && GetBoolArg("-printmining")) + printf("MineProbablePrimeChain() : new sieve (%u/%u@%u%%) ready in %uus\n", sieve.GetCandidateCount(), nSieveSize, sieve.GetProgressPercentage(), (unsigned int) (GetTimeMicros() - nStart)); return false; // sieve generation takes time so return now } - mpz_class mpzHashMultiplier = mpzHash * mpzFixedMultiplier; - mpz_class mpzChainOrigin; - - // Determine the sequence number of the round primorial - unsigned int nPrimorialSeq = 0; - while (vPrimes[nPrimorialSeq + 1] <= nPrimorialMultiplier) - nPrimorialSeq++; - - // Allocate GMP variables for primality tests - CPrimalityTestParams testParams(nBits, nPrimorialSeq); + if (fDebug && GetBoolArg("-printmining2")) + nStart = GetTimeMicros(); - nStart = GetTimeMicros(); - - // References to test parameters - unsigned int& nChainLength = testParams.nChainLength; - unsigned int& nCandidateType = testParams.nCandidateType; - // Number of candidates to be tested during a single call to this function const unsigned int nTestsAtOnce = 500; + mpzHashFixedMult = mpzHash * mpzFixedMultiplier; // Process a part of the candidates while (nTests < nTestsAtOnce && pindexPrev == pindexBest) { - if (!lpsieve->GetNextCandidateMultiplier(nTriedMultiplier, nCandidateType)) + unsigned int nTriedMultiplier = 0; + if (!sieve.GetNextCandidateMultiplier(nTriedMultiplier, nCandidateType)) { // power tests completed for the sieve - //if (fDebug && GetBoolArg("-printmining")) - //printf("MineProbablePrimeChain() : %u tests (%u primes and %u %d-chains) in %uus\n", nTests, nPrimesHit, nChainsHit, nStatsChainLength, (unsigned int) (GetTimeMicros() - nStart)); - psieve.reset(); + if (fDebug && GetBoolArg("-printmining2")) + printf("MineProbablePrimeChain() : %u tests (%u primes) in %uus\n", nTests, nPrimesHit, (unsigned int) (GetTimeMicros() - nStart)); fNewBlock = true; // notify caller to change nonce return false; } nTests++; - mpzChainOrigin = mpzHashMultiplier * nTriedMultiplier; - nChainLength = 0; - if (ProbablePrimeChainTestFast(mpzChainOrigin, testParams)) + mpzChainOrigin = mpzHashFixedMult * nTriedMultiplier; + bool fChainFound = ProbablePrimeChainTestFast(mpzChainOrigin, testParams); + unsigned int nChainPrimeLength = TargetGetLength(nChainLength); + + if (fDebug && GetBoolArg("-debugsieve")) + SieveDebugChecks(nBits, nTriedMultiplier, nCandidateType, mpzHash, mpzFixedMultiplier, mpzChainOrigin); + + // Collect mining statistics + if(nChainPrimeLength >= 1) + { + nPrimesHit++; + vChainsFound[nChainPrimeLength - 1]++; + } + + // Check if a chain was found + if (fChainFound) { mpz_class mpzPrimeChainMultiplier = mpzFixedMultiplier * nTriedMultiplier; CBigNum bnPrimeChainMultiplier; @@ -793,25 +971,12 @@ bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool& printf("nTriedMultiplier = %u\n", nTriedMultiplier); // Debugging printf("Probable prime chain found for block=%s!!\n Target: %s\n Chain: %s\n", block.GetHash().GetHex().c_str(), TargetToString(block.nBits).c_str(), GetPrimeChainName(nCandidateType, nChainLength).c_str()); - nProbableChainLength = nChainLength; return true; } - nProbableChainLength = nChainLength; - if(TargetGetLength(nProbableChainLength) >= 1) - nPrimesHit++; - if(TargetGetLength(nProbableChainLength) >= nStatsChainLength) - nChainsHit++; - // Debugging -#if 0 - if(TargetGetLength(nProbableChainLength) >= 1) - printf("Multiplier %u gave a prime\n", nTriedMultiplier); - else - printf("Multiplier %u gave nothing\n", nTriedMultiplier); -#endif } - //if (fDebug && GetBoolArg("-printmining")) - //printf("MineProbablePrimeChain() : %u tests (%u primes and %u %d-chains) in %uus\n", nTests, nPrimesHit, nChainsHit, nStatsChainLength, (unsigned int) (GetTimeMicros() - nStart)); + if (fDebug && GetBoolArg("-printmining2")) + printf("MineProbablePrimeChain() : %u tests (%u primes) in %uus\n", nTests, nPrimesHit, (unsigned int) (GetTimeMicros() - nStart)); return false; // stop as new block arrived } @@ -862,38 +1027,238 @@ static unsigned int int_invert(unsigned int a, unsigned int nPrime) aux1 = -quotient * aux0 + aux2; } - return (inverse + nPrime) % nPrime; + if (inverse < 0) + inverse += nPrime; + return inverse; +} + +void CSieveOfEratosthenes::ProcessMultiplier(sieve_word_t *vfComposites, const unsigned int nMinMultiplier, const unsigned int nMaxMultiplier, unsigned int *vMultipliers, unsigned int nLayerSeq) +{ + const unsigned int nMultiplierIndexBegin = nLayerSeq * nPrimes; + unsigned int *vMultipliersBegin = &vMultipliers[nMultiplierIndexBegin]; + // Wipe a part of the array first + memset(vfComposites + GetWordNum(nMinMultiplier), 0, (nMaxMultiplier - nMinMultiplier + nWordBits - 1) / nWordBits * sizeof(sieve_word_t)); + const sieve_word_t _nPrimes = nPrimes; + const sieve_word_t _nMaxMultiplier = nMaxMultiplier; + + for (sieve_word_t nPrimeSeq = nMinPrimeSeq; likely(nPrimeSeq < _nPrimes); nPrimeSeq++) + { + sieve_word_t nVariableMultiplier = vMultipliersBegin[nPrimeSeq]; + if (likely(nVariableMultiplier < _nMaxMultiplier)) + { + const sieve_word_t nPrime = vPrimes[nPrimeSeq]; +#ifdef USE_UNROLLED_LOOPS + sieve_signed_t nMaxUnrolled = (sieve_signed_t)_nMaxMultiplier - 4 * (sieve_signed_t)nPrime; + if (nMaxUnrolled < 0) + nMaxUnrolled = 0; +#endif +#if defined(USE_BTS) && defined(USE_BMI2) + const sieve_word_t nShiftCount = nWordBitsLog; +# ifdef USE_UNROLLED_LOOPS + for (; likely(nVariableMultiplier < (sieve_word_t)nMaxUnrolled); nVariableMultiplier += nPrime) + { + sieve_word_t nWord = shrx(nVariableMultiplier, nShiftCount); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + nVariableMultiplier += nPrime; + nWord = shrx(nVariableMultiplier, nShiftCount); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + nVariableMultiplier += nPrime; + nWord = shrx(nVariableMultiplier, nShiftCount); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + nVariableMultiplier += nPrime; + nWord = shrx(nVariableMultiplier, nShiftCount); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + } +# endif + for (; likely(nVariableMultiplier < _nMaxMultiplier); nVariableMultiplier += nPrime) + { + sieve_word_t nWord = shrx(nVariableMultiplier, nShiftCount); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + } +#elif defined(USE_BTS) +# ifdef USE_UNROLLED_LOOPS + for (; likely(nVariableMultiplier < (sieve_word_t)nMaxUnrolled); nVariableMultiplier += nPrime) + { + sieve_word_t nWord = GetWordNum(nVariableMultiplier); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + nVariableMultiplier += nPrime; + nWord = GetWordNum(nVariableMultiplier); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + nVariableMultiplier += nPrime; + nWord = GetWordNum(nVariableMultiplier); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + nVariableMultiplier += nPrime; + nWord = GetWordNum(nVariableMultiplier); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + } +# endif + for (; likely(nVariableMultiplier < _nMaxMultiplier); nVariableMultiplier += nPrime) + { + sieve_word_t nWord = GetWordNum(nVariableMultiplier); + vfComposites[nWord] = bts(nVariableMultiplier, vfComposites[nWord]); + } +#elif defined(USE_ROTATE) + const unsigned int nRotateCount = nPrime % nWordBits; + sieve_word_t lBitMask = GetBitMask(nVariableMultiplier); +# ifdef USE_UNROLLED_LOOPS + for (; likely(nVariableMultiplier < (sieve_word_t)nMaxUnrolled); nVariableMultiplier += nPrime) + { + vfComposites[GetWordNum(nVariableMultiplier)] |= lBitMask; + lBitMask = rotate_left(lBitMask, nRotateCount); + nVariableMultiplier += nPrime; + vfComposites[GetWordNum(nVariableMultiplier)] |= lBitMask; + lBitMask = rotate_left(lBitMask, nRotateCount); + nVariableMultiplier += nPrime; + vfComposites[GetWordNum(nVariableMultiplier)] |= lBitMask; + lBitMask = rotate_left(lBitMask, nRotateCount); + nVariableMultiplier += nPrime; + vfComposites[GetWordNum(nVariableMultiplier)] |= lBitMask; + lBitMask = rotate_left(lBitMask, nRotateCount); + } +# endif + for (; likely(nVariableMultiplier < _nMaxMultiplier); nVariableMultiplier += nPrime) + { + vfComposites[GetWordNum(nVariableMultiplier)] |= lBitMask; + lBitMask = rotate_left(lBitMask, nRotateCount); + } +#else +# ifdef USE_UNROLLED_LOOPS + for (; likely(nVariableMultiplier < (sieve_word_t)nMaxUnrolled); nVariableMultiplier += nPrime) + { + vfComposites[GetWordNum(nVariableMultiplier)] |= GetBitMask(nVariableMultiplier); + nVariableMultiplier += nPrime; + vfComposites[GetWordNum(nVariableMultiplier)] |= GetBitMask(nVariableMultiplier); + nVariableMultiplier += nPrime; + vfComposites[GetWordNum(nVariableMultiplier)] |= GetBitMask(nVariableMultiplier); + nVariableMultiplier += nPrime; + vfComposites[GetWordNum(nVariableMultiplier)] |= GetBitMask(nVariableMultiplier); + } +# endif + for (; likely(nVariableMultiplier < _nMaxMultiplier); nVariableMultiplier += nPrime) + vfComposites[GetWordNum(nVariableMultiplier)] |= GetBitMask(nVariableMultiplier); +#endif + vMultipliersBegin[nPrimeSeq] = nVariableMultiplier; + } + } } -void CSieveOfEratosthenes::ProcessMultiplier(sieve_word_t *vfComposites, const unsigned int nMinMultiplier, const unsigned int nMaxMultiplier, const std::vector& vPrimes, unsigned int *vMultipliers, unsigned int nLayerSeq) +inline void ApplyLayerTWNBoth(unsigned int nMinWord, unsigned int nMaxWord, sieve_word_t *vfCompositeCunningham1, sieve_word_t *vfCompositeCunningham2, sieve_word_t *vfCompositeBiTwin, sieve_word_t *vfLayerCC1, sieve_word_t *vfLayerCC2) { - // Wipe the part of the array first - if (nMinMultiplier < nMaxMultiplier) - memset(vfComposites + GetWordNum(nMinMultiplier), 0, (nMaxMultiplier - nMinMultiplier + nWordBits - 1) / nWordBits * sizeof(sieve_word_t)); +#if defined(USE_AVX2) + const sieve_word_t nMaxWordAVX2 = nMaxWord / (256 / nWordBits); + for (sieve_word_t nWord = nMinWord / (256 / nWordBits); nWord < nMaxWordAVX2; nWord++) + { + const __m256i xCC1Layer = ((__m256i*)vfLayerCC1)[nWord]; + const __m256i xCC2Layer = ((__m256i*)vfLayerCC2)[nWord]; + ((__m256i*)vfCompositeCunningham1)[nWord] |= xCC1Layer; + ((__m256i*)vfCompositeCunningham2)[nWord] |= xCC2Layer; + ((__m256i*)vfCompositeBiTwin)[nWord] |= xCC1Layer | xCC2Layer; + } +#elif defined(USE_SSE2) + const sieve_word_t nMaxWordSSE2 = nMaxWord / (128 / nWordBits); + for (sieve_word_t nWord = nMinWord / (128 / nWordBits); nWord < nMaxWordSSE2; nWord++) + { + const __m128i xCC1Layer = ((__m128i*)vfLayerCC1)[nWord]; + const __m128i xCC2Layer = ((__m128i*)vfLayerCC2)[nWord]; + ((__m128i*)vfCompositeCunningham1)[nWord] |= xCC1Layer; + ((__m128i*)vfCompositeCunningham2)[nWord] |= xCC2Layer; + ((__m128i*)vfCompositeBiTwin)[nWord] |= xCC1Layer | xCC2Layer; + } +#else + for (sieve_word_t nWord = nMinWord; nWord < nMaxWord; nWord++) + { + vfCompositeCunningham1[nWord] |= vfLayerCC1[nWord]; + vfCompositeCunningham2[nWord] |= vfLayerCC2[nWord]; + vfCompositeBiTwin[nWord] |= vfLayerCC1[nWord] | vfLayerCC2[nWord]; + } +#endif +} - for (unsigned int nPrimeSeq = 1; nPrimeSeq < nPrimes; nPrimeSeq++) +inline void ApplyLayerTWNOnlyCC1(unsigned int nMinWord, unsigned int nMaxWord, sieve_word_t *vfCompositeCunningham1, sieve_word_t *vfCompositeCunningham2, sieve_word_t *vfCompositeBiTwin, sieve_word_t *vfLayerCC1, sieve_word_t *vfLayerCC2) +{ +#if defined(USE_AVX2) + const sieve_word_t nMaxWordAVX2 = nMaxWord / (256 / nWordBits); + for (sieve_word_t nWord = nMinWord / (256 / nWordBits); nWord < nMaxWordAVX2; nWord++) + { + const __m256i xCC1Layer = ((__m256i*)vfLayerCC1)[nWord]; + const __m256i xCC2Layer = ((__m256i*)vfLayerCC2)[nWord]; + ((__m256i*)vfCompositeCunningham1)[nWord] |= xCC1Layer; + ((__m256i*)vfCompositeCunningham2)[nWord] |= xCC2Layer; + ((__m256i*)vfCompositeBiTwin)[nWord] |= xCC1Layer; + } +#elif defined(USE_SSE2) + const sieve_word_t nMaxWordSSE2 = nMaxWord / (128 / nWordBits); + for (sieve_word_t nWord = nMinWord / (128 / nWordBits); nWord < nMaxWordSSE2; nWord++) { - const unsigned int nPrime = vPrimes[nPrimeSeq]; - unsigned int nVariableMultiplier = vMultipliers[nPrimeSeq * nSieveLayers + nLayerSeq]; - if (nVariableMultiplier < nMinMultiplier) - nVariableMultiplier += (nMinMultiplier - nVariableMultiplier + nPrime - 1) / nPrime * nPrime; -#ifdef USE_ROTATE - const unsigned int nRotateBits = nPrime % nWordBits; - sieve_word_t lBitMask = GetBitMask(nVariableMultiplier); - for (; nVariableMultiplier < nMaxMultiplier; nVariableMultiplier += nPrime) + const __m128i xCC1Layer = ((__m128i*)vfLayerCC1)[nWord]; + const __m128i xCC2Layer = ((__m128i*)vfLayerCC2)[nWord]; + ((__m128i*)vfCompositeCunningham1)[nWord] |= xCC1Layer; + ((__m128i*)vfCompositeCunningham2)[nWord] |= xCC2Layer; + ((__m128i*)vfCompositeBiTwin)[nWord] |= xCC1Layer; + } +#else + for (sieve_word_t nWord = nMinWord; nWord < nMaxWord; nWord++) { - vfComposites[GetWordNum(nVariableMultiplier)] |= lBitMask; - lBitMask = (lBitMask << nRotateBits) | (lBitMask >> (nWordBits - nRotateBits)); + vfCompositeCunningham1[nWord] |= vfLayerCC1[nWord]; + vfCompositeCunningham2[nWord] |= vfLayerCC2[nWord]; + vfCompositeBiTwin[nWord] |= vfLayerCC1[nWord]; } - vMultipliers[nPrimeSeq * nSieveLayers + nLayerSeq] = nVariableMultiplier; +#endif +} + +inline void ApplyLayerTWNNone(unsigned int nMinWord, unsigned int nMaxWord, sieve_word_t *vfCompositeCunningham1, sieve_word_t *vfCompositeCunningham2, sieve_word_t *vfLayerCC1, sieve_word_t *vfLayerCC2) +{ +#if defined(USE_AVX2) + const sieve_word_t nMaxWordAVX2 = nMaxWord / (256 / nWordBits); + for (sieve_word_t nWord = nMinWord / (256 / nWordBits); nWord < nMaxWordAVX2; nWord++) + { + const __m256i xCC1Layer = ((__m256i*)vfLayerCC1)[nWord]; + const __m256i xCC2Layer = ((__m256i*)vfLayerCC2)[nWord]; + ((__m256i*)vfCompositeCunningham1)[nWord] |= xCC1Layer; + ((__m256i*)vfCompositeCunningham2)[nWord] |= xCC2Layer; + } +#elif defined(USE_SSE2) + const sieve_word_t nMaxWordSSE2 = nMaxWord / (128 / nWordBits); + for (sieve_word_t nWord = nMinWord / (128 / nWordBits); nWord < nMaxWordSSE2; nWord++) + { + const __m128i xCC1Layer = ((__m128i*)vfLayerCC1)[nWord]; + const __m128i xCC2Layer = ((__m128i*)vfLayerCC2)[nWord]; + ((__m128i*)vfCompositeCunningham1)[nWord] |= xCC1Layer; + ((__m128i*)vfCompositeCunningham2)[nWord] |= xCC2Layer; + } #else - for (; nVariableMultiplier < nMaxMultiplier; nVariableMultiplier += nPrime) + for (sieve_word_t nWord = nMinWord; nWord < nMaxWord; nWord++) { - vfComposites[GetWordNum(nVariableMultiplier)] |= GetBitMask(nVariableMultiplier); + vfCompositeCunningham1[nWord] |= vfLayerCC1[nWord]; + vfCompositeCunningham2[nWord] |= vfLayerCC2[nWord]; } - vMultipliers[nPrimeSeq * nSieveLayers + nLayerSeq] = nVariableMultiplier; #endif +} + +inline void CombineBitsets(unsigned int nMinWord, unsigned int nMaxWord, sieve_word_t *vfCandidates, sieve_word_t *vfCompositeCunningham1, sieve_word_t *vfCompositeCunningham2, sieve_word_t *vfCompositeBiTwin) +{ +#if defined(USE_AVX2) + const sieve_word_t nMaxWordAVX2 = nMaxWord / (256 / nWordBits); + for (sieve_word_t nWord = nMinWord / (256 / nWordBits); nWord < nMaxWordAVX2; nWord++) + { + const __m256i xCompositesCC1 = ((__m256i*)vfCompositeCunningham1)[nWord]; + const __m256i xCompositesCC2 = ((__m256i*)vfCompositeCunningham2)[nWord]; + const __m256i xCompositesBiTwin = ((__m256i*)vfCompositeBiTwin)[nWord]; + ((__m256i*)vfCandidates)[nWord] = ~(xCompositesCC1 & xCompositesCC2 & xCompositesBiTwin); } +#elif defined(USE_SSE2) + const sieve_word_t nMaxWordSSE2 = nMaxWord / (128 / nWordBits); + for (sieve_word_t nWord = nMinWord / (128 / nWordBits); nWord < nMaxWordSSE2; nWord++) + { + const __m128i xCompositesCC1 = ((__m128i*)vfCompositeCunningham1)[nWord]; + const __m128i xCompositesCC2 = ((__m128i*)vfCompositeCunningham2)[nWord]; + const __m128i xCompositesBiTwin = ((__m128i*)vfCompositeBiTwin)[nWord]; + ((__m128i*)vfCandidates)[nWord] = ~(xCompositesCC1 & xCompositesCC2 & xCompositesBiTwin); + } +#else + for (sieve_word_t nWord = nMinWord; nWord < nMaxWord; nWord++) + vfCandidates[nWord] = ~(vfCompositeCunningham1[nWord] & vfCompositeCunningham2[nWord] & vfCompositeBiTwin[nWord]); +#endif } // Weave sieve for the next prime in table @@ -902,25 +1267,9 @@ void CSieveOfEratosthenes::ProcessMultiplier(sieve_word_t *vfComposites, const u // False - sieve already completed bool CSieveOfEratosthenes::Weave() { - const unsigned int nMultiplierBytes = nPrimes * nSieveLayers * sizeof(unsigned int); - unsigned int *vCunningham1Multipliers = (unsigned int *)malloc(nMultiplierBytes); - unsigned int *vCunningham2Multipliers = (unsigned int *)malloc(nMultiplierBytes); - - memset(vCunningham1Multipliers, 0xFF, nMultiplierBytes); - memset(vCunningham2Multipliers, 0xFF, nMultiplierBytes); - - // bitsets that can be combined to obtain the final bitset of candidates - sieve_word_t *vfCompositeLayerCC1 = (sieve_word_t *)malloc(nCandidatesBytes); - sieve_word_t *vfCompositeLayerCC2 = (sieve_word_t *)malloc(nCandidatesBytes); - // Check whether fixed multiplier fits in an unsigned long bool fUseLongForFixedMultiplier = mpzFixedMultiplier < ULONG_MAX; - unsigned long nFixedMultiplier; - mpz_class mpzFixedFactor; - if (fUseLongForFixedMultiplier) - nFixedMultiplier = mpzFixedMultiplier.get_ui(); - else - mpzFixedFactor = mpzHash * mpzFixedMultiplier; + unsigned long nFixedMultiplier = mpzFixedMultiplier.get_ui(); unsigned int nCombinedEndSeq = 1; unsigned int nFixedFactorCombinedMod = 0; @@ -946,45 +1295,48 @@ bool CSieveOfEratosthenes::Weave() nFixedFactorCombinedMod = (uint64)nFixedFactorCombinedMod * (nFixedMultiplier % nPrimeCombined) % nPrimeCombined; } else - nFixedFactorCombinedMod = mpz_tdiv_ui(mpzFixedFactor.get_mpz_t(), nPrimeCombined); + nFixedFactorCombinedMod = mpz_tdiv_ui(mpzHashFixedMult.get_mpz_t(), nPrimeCombined); } + // Calculate the modulus of fixed factor in field the defined by nPrime unsigned int nFixedFactorMod = nFixedFactorCombinedMod % nPrime; if (nFixedFactorMod == 0) { // Nothing in the sieve is divisible by this prime continue; } + + // Record the first prime + if (nMinPrimeSeq == 0) + nMinPrimeSeq = nPrimeSeqLocal; + // Find the modulo inverse of fixed factor unsigned int nFixedInverse = int_invert(nFixedFactorMod, nPrime); if (!nFixedInverse) return error("CSieveOfEratosthenes::Weave(): int_invert of fixed factor failed for prime #%u=%u", nPrimeSeqLocal, vPrimes[nPrimeSeqLocal]); unsigned int nTwoInverse = (nPrime + 1) / 2; - // Check whether 32-bit arithmetic can be used for nFixedInverse - const bool fUse32BArithmetic = (UINT_MAX / nTwoInverse) >= nPrime; - - if (fUse32BArithmetic) + // Store a multiplier for each layer { - // Weave the sieve for the prime - for (unsigned int nChainSeq = 0; nChainSeq < nSieveLayers; nChainSeq++) + sieve_word_t nMaxMultiplierIndex = nPrimeSeqLocal + nSieveLayers * nPrimes; + const unsigned int _nPrimes = nPrimes; + for (sieve_word_t nMultiplierIndex = nPrimeSeqLocal; nMultiplierIndex < nMaxMultiplierIndex; nMultiplierIndex += _nPrimes) { - // Find the first number that's divisible by this prime - vCunningham1Multipliers[nPrimeSeqLocal * nSieveLayers + nChainSeq] = nFixedInverse; - vCunningham2Multipliers[nPrimeSeqLocal * nSieveLayers + nChainSeq] = nPrime - nFixedInverse; + // The multiplier gives the first number that is divisible by current prime + unsigned int nCC1Mult = nFixedInverse; + unsigned int nCC2Mult = nPrime - nFixedInverse; - // For next number in chain - nFixedInverse = nFixedInverse * nTwoInverse % nPrime; - } - } - else - { - // Weave the sieve for the prime - for (unsigned int nChainSeq = 0; nChainSeq < nSieveLayers; nChainSeq++) - { - // Find the first number that's divisible by this prime - vCunningham1Multipliers[nPrimeSeqLocal * nSieveLayers + nChainSeq] = nFixedInverse; - vCunningham2Multipliers[nPrimeSeqLocal * nSieveLayers + nChainSeq] = nPrime - nFixedInverse; + // Make sure they are odd + if (nCC1Mult % 2 == 0) nCC1Mult += nPrime; + if (nCC2Mult % 2 == 0) nCC2Mult += nPrime; + + // Divide by two + nCC1Mult /= 2; + nCC2Mult /= 2; + + // Store them + vCunningham1Multipliers[nMultiplierIndex] = nCC1Mult; + vCunningham2Multipliers[nMultiplierIndex] = nCC2Mult; // For next number in chain nFixedInverse = (uint64)nFixedInverse * nTwoInverse % nPrime; @@ -992,28 +1344,20 @@ bool CSieveOfEratosthenes::Weave() } } - // Number of elements that are likely to fit in L1 cache - // NOTE: This needs to be a multiple of nWordBits - const unsigned int nL1CacheElements = 224000; + // Process the array in chunks that fit the L1 cache const unsigned int nArrayRounds = (nSieveSize + nL1CacheElements - 1) / nL1CacheElements; // Calculate the number of CC1 and CC2 layers needed for BiTwin candidates const unsigned int nBiTwinCC1Layers = (nChainLength + 1) / 2; const unsigned int nBiTwinCC2Layers = nChainLength / 2; - // Only 50% of the array is used in extensions - const unsigned int nExtensionsMinMultiplier = nSieveSize / 2; - const unsigned int nExtensionsMinWord = nExtensionsMinMultiplier / nWordBits; - // Loop over each array one at a time for optimal L1 cache performance for (unsigned int j = 0; j < nArrayRounds; j++) { const unsigned int nMinMultiplier = nL1CacheElements * j; - const unsigned int nMaxMultiplier = std::min(nL1CacheElements * (j + 1), nSieveSize); - const unsigned int nExtMinMultiplier = std::max(nMinMultiplier, nExtensionsMinMultiplier); + const unsigned int nMaxMultiplier = std::min(nMinMultiplier + nL1CacheElements, nSieveSize); const unsigned int nMinWord = nMinMultiplier / nWordBits; const unsigned int nMaxWord = (nMaxMultiplier + nWordBits - 1) / nWordBits; - const unsigned int nExtMinWord = std::max(nMinWord, nExtensionsMinWord); if (pindexPrev != pindexBest) break; // new block @@ -1021,47 +1365,18 @@ bool CSieveOfEratosthenes::Weave() for (unsigned int nLayerSeq = 0; nLayerSeq < nSieveLayers; nLayerSeq++) { if (pindexPrev != pindexBest) break; // new block - if (nLayerSeq < nChainLength) - { - ProcessMultiplier(vfCompositeLayerCC1, nMinMultiplier, nMaxMultiplier, vPrimes, vCunningham1Multipliers, nLayerSeq); - ProcessMultiplier(vfCompositeLayerCC2, nMinMultiplier, nMaxMultiplier, vPrimes, vCunningham2Multipliers, nLayerSeq); - } - else - { - // Optimize: First halves of the arrays are not needed in the extensions - ProcessMultiplier(vfCompositeLayerCC1, nExtMinMultiplier, nMaxMultiplier, vPrimes, vCunningham1Multipliers, nLayerSeq); - ProcessMultiplier(vfCompositeLayerCC2, nExtMinMultiplier, nMaxMultiplier, vPrimes, vCunningham2Multipliers, nLayerSeq); - } + ProcessMultiplier(vfCompositeLayerCC1, nMinMultiplier, nMaxMultiplier, vCunningham1Multipliers, nLayerSeq); + ProcessMultiplier(vfCompositeLayerCC2, nMinMultiplier, nMaxMultiplier, vCunningham2Multipliers, nLayerSeq); // Apply the layer to the primary sieve arrays if (nLayerSeq < nChainLength) { if (nLayerSeq < nBiTwinCC2Layers) - { - for (unsigned int nWord = nMinWord; nWord < nMaxWord; nWord++) - { - vfCompositeCunningham1[nWord] |= vfCompositeLayerCC1[nWord]; - vfCompositeCunningham2[nWord] |= vfCompositeLayerCC2[nWord]; - vfCompositeBiTwin[nWord] |= vfCompositeLayerCC1[nWord] | vfCompositeLayerCC2[nWord]; - } - } + ApplyLayerTWNBoth(nMinWord, nMaxWord, vfCompositeCunningham1, vfCompositeCunningham2, vfCompositeBiTwin, vfCompositeLayerCC1, vfCompositeLayerCC2); else if (nLayerSeq < nBiTwinCC1Layers) - { - for (unsigned int nWord = nMinWord; nWord < nMaxWord; nWord++) - { - vfCompositeCunningham1[nWord] |= vfCompositeLayerCC1[nWord]; - vfCompositeCunningham2[nWord] |= vfCompositeLayerCC2[nWord]; - vfCompositeBiTwin[nWord] |= vfCompositeLayerCC1[nWord]; - } - } + ApplyLayerTWNOnlyCC1(nMinWord, nMaxWord, vfCompositeCunningham1, vfCompositeCunningham2, vfCompositeBiTwin, vfCompositeLayerCC1, vfCompositeLayerCC2); else - { - for (unsigned int nWord = nMinWord; nWord < nMaxWord; nWord++) - { - vfCompositeCunningham1[nWord] |= vfCompositeLayerCC1[nWord]; - vfCompositeCunningham2[nWord] |= vfCompositeLayerCC2[nWord]; - } - } + ApplyLayerTWNNone(nMinWord, nMaxWord, vfCompositeCunningham1, vfCompositeCunningham2, vfCompositeLayerCC1, vfCompositeLayerCC2); } // Apply the layer to extensions @@ -1075,58 +1390,33 @@ bool CSieveOfEratosthenes::Weave() sieve_word_t *vfExtCC2 = vfExtendedCompositeCunningham2 + nExtensionSeq * nCandidatesWords; sieve_word_t *vfExtTWN = vfExtendedCompositeBiTwin + nExtensionSeq * nCandidatesWords; if (nLayerExtendedSeq < nBiTwinCC2Layers) - { - for (unsigned int nWord = nExtMinWord; nWord < nMaxWord; nWord++) - { - vfExtCC1[nWord] |= vfCompositeLayerCC1[nWord]; - vfExtCC2[nWord] |= vfCompositeLayerCC2[nWord]; - vfExtTWN[nWord] |= vfCompositeLayerCC1[nWord] | vfCompositeLayerCC2[nWord]; - } - } + ApplyLayerTWNBoth(nMinWord, nMaxWord, vfExtCC1, vfExtCC2, vfExtTWN, vfCompositeLayerCC1, vfCompositeLayerCC2); else if (nLayerExtendedSeq < nBiTwinCC1Layers) - { - for (unsigned int nWord = nExtMinWord; nWord < nMaxWord; nWord++) - { - vfExtCC1[nWord] |= vfCompositeLayerCC1[nWord]; - vfExtCC2[nWord] |= vfCompositeLayerCC2[nWord]; - vfExtTWN[nWord] |= vfCompositeLayerCC1[nWord]; - } - } + ApplyLayerTWNOnlyCC1(nMinWord, nMaxWord, vfExtCC1, vfExtCC2, vfExtTWN, vfCompositeLayerCC1, vfCompositeLayerCC2); else - { - for (unsigned int nWord = nExtMinWord; nWord < nMaxWord; nWord++) - { - vfExtCC1[nWord] |= vfCompositeLayerCC1[nWord]; - vfExtCC2[nWord] |= vfCompositeLayerCC2[nWord]; - } - } + ApplyLayerTWNNone(nMinWord, nMaxWord, vfExtCC1, vfExtCC2, vfCompositeLayerCC1, vfCompositeLayerCC2); } } } // Combine the bitsets // vfCandidates = ~(vfCompositeCunningham1 & vfCompositeCunningham2 & vfCompositeBiTwin) - for (unsigned int i = nMinWord; i < nMaxWord; i++) - vfCandidates[i] = ~(vfCompositeCunningham1[i] & vfCompositeCunningham2[i] & vfCompositeBiTwin[i]); + CombineBitsets(nMinWord, nMaxWord, vfCandidates, vfCompositeCunningham1, vfCompositeCunningham2, vfCompositeBiTwin); // Combine the extended bitsets - for (unsigned int j = 0; j < nSieveExtensions; j++) - for (unsigned int i = nExtMinWord; i < nMaxWord; i++) - vfExtendedCandidates[j * nCandidatesWords + i] = ~( - vfExtendedCompositeCunningham1[j * nCandidatesWords + i] & - vfExtendedCompositeCunningham2[j * nCandidatesWords + i] & - vfExtendedCompositeBiTwin[j * nCandidatesWords + i]); + for (unsigned int j = 0, nExtOffset = 0; j < nSieveExtensions; j++, nExtOffset += nCandidatesWords) + { + sieve_word_t *vfExtCandidates = &vfExtendedCandidates[nExtOffset]; + sieve_word_t *vfExtCompositeCC1 = &vfExtendedCompositeCunningham1[nExtOffset]; + sieve_word_t *vfExtCompositeCC2 = &vfExtendedCompositeCunningham2[nExtOffset]; + sieve_word_t *vfExtCompositeTWN = &vfExtendedCompositeBiTwin[nExtOffset]; + CombineBitsets(nMinWord, nMaxWord, vfExtCandidates, vfExtCompositeCC1, vfExtCompositeCC2, vfExtCompositeTWN); + } } // The sieve has been partially weaved this->nPrimeSeq = nPrimes - 1; - free(vfCompositeLayerCC1); - free(vfCompositeLayerCC2); - - free(vCunningham1Multipliers); - free(vCunningham2Multipliers); - return false; } @@ -1134,7 +1424,7 @@ static const double dLogTwo = log(2.0); static const double dLogOneAndHalf = log(1.5); // Estimate the probability of primality for a number in a candidate chain -double EstimateCandidatePrimeProbability(unsigned int nPrimorialMultiplier, unsigned int nChainPrimeNum) +double EstimateCandidatePrimeProbability(unsigned int nPrimorialMultiplier, unsigned int nChainPrimeNum, unsigned int nMiningProtocol) { // h * q# / r# * s is prime with probability 1/log(h * q# / r# * s), // (prime number theorem) @@ -1151,22 +1441,55 @@ double EstimateCandidatePrimeProbability(unsigned int nPrimorialMultiplier, unsi // statistically independent after running the sieve, which might not be // true, but nontheless it's a reasonable model of the chances of finding // prime chains. - const unsigned int nSieveWeaveOptimalPrime = vPrimes[(unsigned int) ((uint64) nSievePercentage * vPrimes.size() / 100) - 1]; + const unsigned int nSieveWeaveOptimalPrime = vPrimes[nSieveFilterPrimes - 1]; const unsigned int nAverageCandidateMultiplier = nSieveSize / 2; double dFixedMultiplier = 1.0; for (unsigned int i = 0; vPrimes[i] <= nPrimorialMultiplier; i++) dFixedMultiplier *= vPrimes[i]; - for (unsigned int i = 0; vPrimes[i] <= nPrimorialHashFactor; i++) - dFixedMultiplier /= vPrimes[i]; + if (nMiningProtocol < 2) + { + for (unsigned int i = 0; vPrimes[i] <= nPrimorialHashFactor; i++) + dFixedMultiplier /= vPrimes[i]; + } - double dExtendedSieveWeightedSum = 0.5 * nSieveSize; + double dExtendedSieveWeightedSum = nSieveSize; double dExtendedSieveCandidates = nSieveSize; for (unsigned int i = 0; i < nSieveExtensions; i++) { - dExtendedSieveWeightedSum += 0.75 * (nSieveSize * (2 << i)); - dExtendedSieveCandidates += nSieveSize / 2; + dExtendedSieveWeightedSum += nSieveSize * (2 << i); + dExtendedSieveCandidates += nSieveSize; } const double dExtendedSieveAverageMultiplier = dExtendedSieveWeightedSum / dExtendedSieveCandidates; return (1.781072 * log((double)std::max(1u, nSieveWeaveOptimalPrime)) / (255.0 * dLogTwo + dLogOneAndHalf + log(dFixedMultiplier) + log(nAverageCandidateMultiplier) + dLogTwo * nChainPrimeNum + log(dExtendedSieveAverageMultiplier))); } + +// Esimate the prime probablity of numbers that haven't been sieved +double EstimateNormalPrimeProbability(unsigned int nPrimorialMultiplier, unsigned int nChainPrimeNum, unsigned int nMiningProtocol) +{ + const unsigned int nAverageCandidateMultiplier = nSieveSize / 2; + double dFixedMultiplier = 1.0; + for (unsigned int i = 0; vPrimes[i] <= nPrimorialMultiplier; i++) + dFixedMultiplier *= vPrimes[i]; + if (nMiningProtocol < 2) + { + for (unsigned int i = 0; vPrimes[i] <= nPrimorialHashFactor; i++) + dFixedMultiplier /= vPrimes[i]; + } + + double dExtendedSieveWeightedSum = nSieveSize; + double dExtendedSieveCandidates = nSieveSize; + for (unsigned int i = 0; i < nSieveExtensions; i++) + { + dExtendedSieveWeightedSum += nSieveSize * (2 << i); + dExtendedSieveCandidates += nSieveSize; + } + const double dExtendedSieveAverageMultiplier = dExtendedSieveWeightedSum / dExtendedSieveCandidates; + + // The primorial is implicitly filtering out the first few prime factors + double dPrimorialBoost = 1.0; + for (unsigned int i = 0; vPrimes[i] <= nPrimorialMultiplier; i++) + dPrimorialBoost *= (double)vPrimes[i] / (vPrimes[i] - 1); + + return (dPrimorialBoost / (255.0 * dLogTwo + dLogOneAndHalf + log(dFixedMultiplier) + log(nAverageCandidateMultiplier) + dLogTwo * nChainPrimeNum + log(dExtendedSieveAverageMultiplier))); +} diff --git a/src/prime.h b/src/prime.h index 3f268d7e..959035bc 100644 --- a/src/prime.h +++ b/src/prime.h @@ -6,10 +6,12 @@ #define PRIMECOIN_PRIME_H #include "main.h" +#include "base58.h" #include #include #include +#include /**********************/ /* PRIMECOIN PROTOCOL */ @@ -18,17 +20,21 @@ extern std::vector vPrimes; static const unsigned int nMaxSieveExtensions = 20; static const unsigned int nMinSieveExtensions = 0; -static const unsigned int nDefaultSieveExtensions = 9; +static const unsigned int nDefaultSieveExtensions = 10; static const unsigned int nDefaultSieveExtensionsTestnet = 4; extern unsigned int nSieveExtensions; -static const unsigned int nMaxSievePercentage = 100; -static const unsigned int nDefaultSievePercentage = 10; -static const unsigned int nMinSievePercentage = 1; -extern unsigned int nSievePercentage; +static const unsigned int nMaxSieveFilterPrimes = 78498u; // size of prime table +static const unsigned int nDefaultSieveFilterPrimes = 14000u; +static const unsigned int nMinSieveFilterPrimes = 1000u; +extern unsigned int nSieveFilterPrimes; static const unsigned int nMaxSieveSize = 10000000u; -static const unsigned int nDefaultSieveSize = 1000000u; +static const unsigned int nDefaultSieveSize = 1376256u; static const unsigned int nMinSieveSize = 100000u; extern unsigned int nSieveSize; +static const unsigned int nMaxL1CacheSize = 128000u; +static const unsigned int nDefaultL1CacheSize = 28672u; +static const unsigned int nMinL1CacheSize = 12000u; +extern unsigned int nL1CacheSize; static const uint256 hashBlockHeaderLimit = (uint256(1) << 255); static const CBigNum bnOne = 1; static const CBigNum bnPrimeMax = (bnOne << 2000) - 1; @@ -37,15 +43,41 @@ static const mpz_class mpzOne = 1; static const mpz_class mpzTwo = 2; static const mpz_class mpzPrimeMax = (mpzOne << 2000) - 1; static const mpz_class mpzPrimeMin = (mpzOne << 255); - -// Estimate how many 5-chains are found per hour -static const unsigned int nStatsChainLength = 5; +static const unsigned int nPrimorialHashFactor = 7; +static const unsigned int nInitialPrimorialMultiplier = 47; +static const unsigned int nInitialPrimorialMultiplierTestnet = 17; + +// Mining statistics +static const unsigned int nMaxChainLength = 24; +extern uint64 nTotalTests; +extern unsigned int nTotalBlocksFound; +extern std::vector vTotalChainsFound; +extern boost::timer::cpu_timer minerTimer; +static const unsigned int nDefaultSieveTargetLength = -1; +extern int nSieveTargetLength; + +// Primecoin HP: Optional automatic donations with every block found +static const std::string strDefaultDonationPercentage = "1.0"; +static const double dMinDonationPercentage = 0.1; +static const double dMaxDonationPercentage = 99.9; +static const std::string strDefaultDonationAddress = "DSSHsB1R8mrZd1ujhxcPqQaqAu2cNZsCNn"; +static const std::string strDefaultDonationAddressTestnet = "mpriMeHPGWdXYZNtM3ib4WqaViKnrZafkY"; +extern CBitcoinAddress donationAddress; +extern double dDonationPercentage; extern unsigned int nTargetInitialLength; extern unsigned int nTargetMinLength; // Generate small prime table void GeneratePrimeTable(); +// Reset the miner statistics +void ResetMinerStatistics(); +// Initialize the miner +void InitPrimeMiner(); +// Print miner statistics +void PrintMinerStatistics(); +// Print compact statistics +void PrintCompactStatistics(volatile unsigned int vFoundChainCounter[nMaxChainLength]); // Get next prime number of p bool PrimeTableGetNextPrime(unsigned int& p); // Get previous prime number of p @@ -75,6 +107,7 @@ static const uint64 nFractionalDifficultyMax = (1llu << (nFractionalBits + 32)); static const uint64 nFractionalDifficultyMin = (1llu << 32); static const uint64 nFractionalDifficultyThreshold = (1llu << (8 + 32)); static const unsigned int nWorkTransitionRatio = 32; +static const unsigned int nWorkTransitionRatioLog = 5; // log_2(32) = 5 unsigned int TargetGetLimit(); unsigned int TargetGetInitial(); unsigned int TargetGetLength(unsigned int nBits); @@ -110,31 +143,188 @@ std::string GetPrimeOriginPrimorialForm(CBigNum& bnPrimeChainOrigin); /* PRIMECOIN MINING */ /********************/ +class CSieveOfEratosthenes; +class CPrimalityTestParams; + // Mine probable prime chain of form: n = h * p# +/- 1 -bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool& fNewBlock, unsigned int& nTriedMultiplier, unsigned int& nProbableChainLength, unsigned int& nTests, unsigned int& nPrimesHit, unsigned int& nChainsHit, mpz_class& mpzHash, unsigned int nPrimorialMultiplier, int64& nSieveGenTime, CBlockIndex* pindexPrev); +bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool& fNewBlock, unsigned int& nTests, unsigned int& nPrimesHit, mpz_class& mpzHash, CBlockIndex* pindexPrev, unsigned int vChainsFound[nMaxChainLength], CSieveOfEratosthenes& sieve, CPrimalityTestParams& testParams); + +// Perform Fermat test with trial division +// Return values: +// true - passes trial division test and Fermat test; probable prime +// false - failed either trial division or Fermat test; composite +bool ProbablePrimalityTestWithTrialDivision(const mpz_class& mpzCandidate, unsigned int nTrialDivisionLimit, CPrimalityTestParams& testParams); // Estimate the probability of primality for a number in a candidate chain -double EstimateCandidatePrimeProbability(unsigned int nPrimorialMultiplier, unsigned int nChainPrimeNum); +double EstimateCandidatePrimeProbability(unsigned int nPrimorialMultiplier, unsigned int nChainPrimeNum, unsigned int nMiningProtocol); +// Esimate the prime probablity of numbers that haven't been sieved +double EstimateNormalPrimeProbability(unsigned int nPrimorialMultiplier, unsigned int nChainPrimeNum, unsigned int nMiningProtocol); + +/* + * Use GCC-style builtin functions such as + * __builtin_popcountl and + * __sync_add_and_fetch + */ +#if defined(__GNUC__) || defined(__clang__) +# define USE_GCC_BUILTINS +#endif + +#ifdef USE_GCC_BUILTINS +# define likely(x) __builtin_expect(!!(x),1) +# define unlikely(x) __builtin_expect(!!(x),0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +#endif #if defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__x86_64__) || defined(_M_X64) -#define USE_ROTATE +# define USE_ROTATE +# if defined(__GNUC__) || defined(__clang__) +# define USE_ASM +# define USE_INTRINSICS +# define USE_BTS +# endif +#endif + +// Unrolled loops only on x86-64 +// Probably too much register pressure on x86 +#if defined(__x86_64__) || defined(_M_X64) +# define USE_UNROLLED_LOOPS +#endif + +#ifdef USE_INTRINSICS +# include +#endif + +// Check if the target platform is 64-bit +#if defined(__x86_64__) || defined(_M_X64) +#define USE_64BIT +typedef unsigned long long sieve_word_t; +typedef signed long long sieve_signed_t; +#else +typedef unsigned int sieve_word_t; +typedef signed int sieve_signed_t; +#endif + +static const unsigned int nWordBits = 8 * sizeof(sieve_word_t); +static const unsigned int nWordBitsLog = (nWordBits == 64) ? 6 : 5; + +#ifdef USE_BTS +// The bts instruction should be very fast starting from Intel Core 2 +inline sieve_word_t bts(sieve_word_t nr, sieve_word_t bits) +{ + asm ("bts %1, %0" + : "+r" (bits) + : "Ir" (nr) + : "cc"); + return bits; +} +#endif + +#ifdef USE_ROTATE +inline sieve_word_t rotate_left(sieve_word_t bits, unsigned int count) +{ +#ifdef USE_ASM + asm("rol %1, %0" + : "+r" (bits) + : "c" ((uint8_t)count) + : "cc"); + return bits; +#else + // NOTE: At least LLVM doesn't always recognize this pattern + return (bits << count) | (bits >> (nWordBits - count)); +#endif +} +#endif + +#if defined(USE_ASM) && defined(__BMI2__) +# define USE_BMI2 +#endif + +#if defined(USE_INTRINSICS) && defined(__SSE2__) +# define USE_SSE2 +#endif + +#if defined(USE_INTRINSICS) && defined(__AVX2__) +# define USE_AVX2 +#endif + +#if defined(USE_AVX2) +const unsigned int nRequiredAlignment = 256; +#elif defined(USE_SSE2) +const unsigned int nRequiredAlignment = 128; +#elif defined(USE_64BIT) +const unsigned int nRequiredAlignment = 64; +#else +const unsigned int nRequiredAlignment = 32; +#endif + +#ifdef USE_BMI2 +inline sieve_word_t shrx(sieve_word_t bits, sieve_word_t count) +{ + sieve_word_t result; + asm("shrx %2, %1, %0" + :"=r" (result) + :"r" (bits), "r" (count)); + return result; +} + +inline sieve_word_t shlx(sieve_word_t bits, sieve_word_t count) +{ + sieve_word_t result; + asm("shlx %2, %1, %0" + :"=r" (result) + :"r" (bits), "r" (count)); + return result; +} #endif -typedef unsigned long sieve_word_t; +class CPrimalityTestParams +{ +public: + // GMP C++ variables + mpz_class mpzHashFixedMult; + mpz_class mpzChainOrigin; + mpz_class mpzOriginMinusOne; + mpz_class mpzOriginPlusOne; + mpz_class mpzN; + mpz_class mpzNMinusOne; + mpz_class mpzBase; + mpz_class mpzR; + mpz_class mpzR2; + mpz_class mpzE; + mpz_class mpzFrac; + + // Values specific to a round + unsigned int nBits; + unsigned int nCandidateType; + + // Results + unsigned int nChainLength; + + CPrimalityTestParams() + { + nBits = 0; + nCandidateType = 0; + nChainLength = 0; + } +}; // Sieve of Eratosthenes for proof-of-work mining // // Includes the sieve extension feature from jhPrimeminer by jh000 // -// A layer of the sieve determines whether the CC1 or CC2 chain members near the -// origin fixed_multiplier * candidate_multiplier * 2^k are known to be -// composites. +// Layer k of the sieve determines whether numbers of the form +// hash * primorial * candidate * 2^k - 1 and +// hash * primorial * candidate * 2^k + 1 +// are known to be composites. // -// The default sieve is composed of layers 1 .. nChainLength. +// The default sieve is composed of layers 1 .. nChainLength. The multipliers +// in the default sieve are all odd. // // An extension i is composed of layers i .. i + nChainLength. The candidates -// indexes from the extensions are multiplied by 2^i. The first half of the -// candidates are covered by the default sieve and previous extensions. +// indexes from the extensions are multiplied by 2^i. Therefore, the resulting +// multipliers are always even. // // The larger numbers in the extensions have a slightly smaller probability of // being primes and take slightly longer to test but they can be calculated very @@ -142,17 +332,32 @@ typedef unsigned long sieve_word_t; class CSieveOfEratosthenes { unsigned int nSieveSize; // size of the sieve - unsigned int nSievePercentage; // weave up to a percentage of primes + unsigned int nSieveFilterPrimes; // filter a certain number of primes unsigned int nSieveExtensions; // extend the sieve a given number of times unsigned int nBits; // target of the prime chain to search for mpz_class mpzHash; // hash of the block header mpz_class mpzFixedMultiplier; // fixed round multiplier + mpz_class mpzHashFixedMult; // mpzHash * mpzFixedMultiplier + + // raw and possibly unaligned pointers + sieve_word_t *vfRawCandidates; + sieve_word_t *vfRawCompositeBiTwin; + sieve_word_t *vfRawCompositeCunningham1; + sieve_word_t *vfRawCompositeCunningham2; + sieve_word_t *vfRawCompositeLayerCC1; + sieve_word_t *vfRawCompositeLayerCC2; + sieve_word_t *vfRawExtendedCandidates; + sieve_word_t *vfRawExtendedCompositeBiTwin; + sieve_word_t *vfRawExtendedCompositeCunningham1; + sieve_word_t *vfRawExtendedCompositeCunningham2; // final set of candidates for probable primality checking sieve_word_t *vfCandidates; sieve_word_t *vfCompositeBiTwin; sieve_word_t *vfCompositeCunningham1; sieve_word_t *vfCompositeCunningham2; + sieve_word_t *vfCompositeLayerCC1; + sieve_word_t *vfCompositeLayerCC2; // extended sets sieve_word_t *vfExtendedCandidates; @@ -160,7 +365,10 @@ class CSieveOfEratosthenes sieve_word_t *vfExtendedCompositeCunningham1; sieve_word_t *vfExtendedCompositeCunningham2; - static const unsigned int nWordBits = 8 * sizeof(sieve_word_t); + // divisible multipliers + unsigned int *vCunningham1Multipliers; + unsigned int *vCunningham2Multipliers; + unsigned int nCandidatesWords; unsigned int nCandidatesBytes; @@ -174,9 +382,19 @@ class CSieveOfEratosthenes unsigned int nChainLength; // target chain length unsigned int nSieveLayers; // sieve layers unsigned int nPrimes; // number of times to weave the sieve + unsigned int nL1CacheElements; // number of bits that can be stored in L1 cache + unsigned int nMinPrimeSeq; // smallest prime which will be used for sieving CBlockIndex* pindexPrev; + // previous parameters + unsigned int nCandidatesBytesPrev; + unsigned int nSieveExtensionsPrev; + unsigned int nMultiplierBytesPrev; + + bool fIsReady; + bool fIsDepleted; + unsigned int GetWordNum(unsigned int nBitNum) { return nBitNum / nWordBits; } @@ -185,61 +403,194 @@ class CSieveOfEratosthenes return (sieve_word_t)1 << (nBitNum % nWordBits); } - void ProcessMultiplier(sieve_word_t *vfComposites, const unsigned int nMinMultiplier, const unsigned int nMaxMultiplier, const std::vector& vPrimes, unsigned int *vMultipliers, unsigned int nLayerSeq); + void ProcessMultiplier(sieve_word_t *vfComposites, const unsigned int nMinMultiplier, const unsigned int nMaxMultiplier, unsigned int *vMultipliers, unsigned int nLayerSeq); + + void freeArrays() + { + if (vfRawCandidates) + free(vfRawCandidates); + if (vfRawCompositeBiTwin) + free(vfRawCompositeBiTwin); + if (vfRawCompositeCunningham1) + free(vfRawCompositeCunningham1); + if (vfRawCompositeCunningham2) + free(vfRawCompositeCunningham2); + if (vfRawCompositeLayerCC1) + free(vfRawCompositeLayerCC1); + if (vfRawCompositeLayerCC2) + free(vfRawCompositeLayerCC2); + if (vfRawExtendedCandidates) + free(vfRawExtendedCandidates); + if (vfRawExtendedCompositeBiTwin) + free(vfRawExtendedCompositeBiTwin); + if (vfRawExtendedCompositeCunningham1) + free(vfRawExtendedCompositeCunningham1); + if (vfRawExtendedCompositeCunningham2) + free(vfRawExtendedCompositeCunningham2); + if (vCunningham1Multipliers) + free(vCunningham1Multipliers); + if (vCunningham2Multipliers) + free(vCunningham2Multipliers); + vfRawCandidates = NULL; + vfRawCompositeBiTwin = NULL; + vfRawCompositeCunningham1 = NULL; + vfRawCompositeCunningham2 = NULL; + vfRawCompositeLayerCC1 = NULL; + vfRawCompositeLayerCC2 = NULL; + vfRawExtendedCandidates = NULL; + vfRawExtendedCompositeBiTwin = NULL; + vfRawExtendedCompositeCunningham1 = NULL; + vfRawExtendedCompositeCunningham2 = NULL; + vfCandidates = NULL; + vfCompositeBiTwin = NULL; + vfCompositeCunningham1 = NULL; + vfCompositeCunningham2 = NULL; + vfCompositeLayerCC1 = NULL; + vfCompositeLayerCC2 = NULL; + vfExtendedCandidates = NULL; + vfExtendedCompositeBiTwin = NULL; + vfExtendedCompositeCunningham1 = NULL; + vfExtendedCompositeCunningham2 = NULL; + } public: - CSieveOfEratosthenes(unsigned int nSieveSize, unsigned int nSievePercentage, unsigned int nSieveExtensions, unsigned int nBits, mpz_class& mpzHash, mpz_class& mpzFixedMultiplier, CBlockIndex* pindexPrev) + CSieveOfEratosthenes() + { + nSieveSize = 0; + nSieveFilterPrimes = 0; + nSieveExtensions = 0; + nBits = 0; + mpzHash = 0; + mpzFixedMultiplier = 0; + mpzHashFixedMult = 0; + vfRawCandidates = NULL; + vfRawCompositeBiTwin = NULL; + vfRawCompositeCunningham1 = NULL; + vfRawCompositeCunningham2 = NULL; + vfRawCompositeLayerCC1 = NULL; + vfRawCompositeLayerCC2 = NULL; + vfRawExtendedCandidates = NULL; + vfRawExtendedCompositeBiTwin = NULL; + vfRawExtendedCompositeCunningham1 = NULL; + vfRawExtendedCompositeCunningham2 = NULL; + vfCandidates = NULL; + vfCompositeBiTwin = NULL; + vfCompositeCunningham1 = NULL; + vfCompositeCunningham2 = NULL; + vfCompositeLayerCC1 = NULL; + vfCompositeLayerCC2 = NULL; + vfExtendedCandidates = NULL; + vfExtendedCompositeBiTwin = NULL; + vfExtendedCompositeCunningham1 = NULL; + vfExtendedCompositeCunningham2 = NULL; + vCunningham1Multipliers = NULL; + vCunningham2Multipliers = NULL; + nCandidatesWords = 0; + nCandidatesBytes = 0; + nCandidatesBytesPrev = 0; + nSieveExtensionsPrev = 0; + nMultiplierBytesPrev = 0; + nPrimeSeq = 0; + nCandidateCount = 0; + nCandidateMultiplier = 0; + nCandidateIndex = 0; + fCandidateIsExtended = false; + nCandidateActiveExtension = 0; + nChainLength = 0; + nSieveLayers = 0; + nPrimes = 0; + nL1CacheElements = 0; + nMinPrimeSeq = 0; + pindexPrev = NULL; + fIsReady = false; + fIsDepleted = true; + } + + ~CSieveOfEratosthenes() + { + freeArrays(); + } + + void Reset(unsigned int nSieveSize, unsigned int nSieveFilterPrimes, unsigned int nSieveExtensions, unsigned int nL1CacheSize, unsigned int nBits, mpz_class& mpzHash, mpz_class& mpzFixedMultiplier, CBlockIndex* pindexPrev) { this->nSieveSize = nSieveSize; - this->nSievePercentage = nSievePercentage; + this->nSieveFilterPrimes = nSieveFilterPrimes; this->nSieveExtensions = nSieveExtensions; + nL1CacheElements = nL1CacheSize * 8; this->nBits = nBits; this->mpzHash = mpzHash; this->mpzFixedMultiplier = mpzFixedMultiplier; this->pindexPrev = pindexPrev; + mpzHashFixedMult = mpzHash * mpzFixedMultiplier; nPrimeSeq = 0; nCandidateCount = 0; nCandidateMultiplier = 0; nCandidateIndex = 0; fCandidateIsExtended = false; nCandidateActiveExtension = 0; - nCandidatesWords = (nSieveSize + nWordBits - 1) / nWordBits; + nCandidatesWords = (nSieveSize + nRequiredAlignment - 1) / nRequiredAlignment * (nRequiredAlignment / nWordBits); nCandidatesBytes = nCandidatesWords * sizeof(sieve_word_t); - vfCandidates = (sieve_word_t *)malloc(nCandidatesBytes); - vfCompositeBiTwin = (sieve_word_t *)malloc(nCandidatesBytes); - vfCompositeCunningham1 = (sieve_word_t *)malloc(nCandidatesBytes); - vfCompositeCunningham2 = (sieve_word_t *)malloc(nCandidatesBytes); + nChainLength = TargetGetLength(nBits); + nMinPrimeSeq = 0; + + // Override target length if requested + if (nSieveTargetLength > 0) + nChainLength = nSieveTargetLength; + nSieveLayers = nChainLength + nSieveExtensions; + + // Filter only a certain number of prime factors + // Most composites are still found + nPrimes = nSieveFilterPrimes; + const unsigned int nMultiplierBytes = nPrimes * nSieveLayers * sizeof(unsigned int); + + // Allocate arrays if parameters have changed + if (nCandidatesBytes != nCandidatesBytesPrev || nSieveExtensions != nSieveExtensionsPrev || nMultiplierBytes != nMultiplierBytesPrev) + { + nCandidatesBytesPrev = nCandidatesBytes; + nSieveExtensionsPrev = nSieveExtensions; + nMultiplierBytesPrev = nMultiplierBytes; + freeArrays(); + vfRawCandidates = (sieve_word_t *)malloc(nCandidatesBytes + nRequiredAlignment); + vfRawCompositeBiTwin = (sieve_word_t *)malloc(nCandidatesBytes + nRequiredAlignment); + vfRawCompositeCunningham1 = (sieve_word_t *)malloc(nCandidatesBytes + nRequiredAlignment); + vfRawCompositeCunningham2 = (sieve_word_t *)malloc(nCandidatesBytes + nRequiredAlignment); + vfRawCompositeLayerCC1 = (sieve_word_t *)malloc(nCandidatesBytes + nRequiredAlignment); + vfRawCompositeLayerCC2 = (sieve_word_t *)malloc(nCandidatesBytes + nRequiredAlignment); + vfRawExtendedCandidates = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes + nRequiredAlignment); + vfRawExtendedCompositeBiTwin = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes + nRequiredAlignment); + vfRawExtendedCompositeCunningham1 = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes + nRequiredAlignment); + vfRawExtendedCompositeCunningham2 = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes + nRequiredAlignment); + vCunningham1Multipliers = (unsigned int *)malloc(nMultiplierBytes); + vCunningham2Multipliers = (unsigned int *)malloc(nMultiplierBytes); +#define ALIGN_PTR(x) ((void *)(((uintptr_t)(x) + nRequiredAlignment - 1) / nRequiredAlignment * nRequiredAlignment)) + vfCandidates = (sieve_word_t *)ALIGN_PTR(vfRawCandidates); + vfCompositeBiTwin = (sieve_word_t *)ALIGN_PTR(vfRawCompositeBiTwin); + vfCompositeCunningham1 = (sieve_word_t *)ALIGN_PTR(vfRawCompositeCunningham1); + vfCompositeCunningham2 = (sieve_word_t *)ALIGN_PTR(vfRawCompositeCunningham2); + vfCompositeLayerCC1 = (sieve_word_t *)ALIGN_PTR(vfRawCompositeLayerCC1); + vfCompositeLayerCC2 = (sieve_word_t *)ALIGN_PTR(vfRawCompositeLayerCC2); + vfExtendedCandidates = (sieve_word_t *)ALIGN_PTR(vfRawExtendedCandidates); + vfExtendedCompositeBiTwin = (sieve_word_t *)ALIGN_PTR(vfRawExtendedCompositeBiTwin); + vfExtendedCompositeCunningham1 = (sieve_word_t *)ALIGN_PTR(vfRawExtendedCompositeCunningham1); + vfExtendedCompositeCunningham2 = (sieve_word_t *)ALIGN_PTR(vfRawExtendedCompositeCunningham2); + } + + // Initialize arrays memset(vfCandidates, 0, nCandidatesBytes); memset(vfCompositeBiTwin, 0, nCandidatesBytes); memset(vfCompositeCunningham1, 0, nCandidatesBytes); memset(vfCompositeCunningham2, 0, nCandidatesBytes); - vfExtendedCandidates = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes); - vfExtendedCompositeBiTwin = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes); - vfExtendedCompositeCunningham1 = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes); - vfExtendedCompositeCunningham2 = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes); + memset(vfCompositeLayerCC1, 0, nCandidatesBytes); + memset(vfCompositeLayerCC2, 0, nCandidatesBytes); memset(vfExtendedCandidates, 0, nSieveExtensions * nCandidatesBytes); memset(vfExtendedCompositeBiTwin, 0, nSieveExtensions * nCandidatesBytes); memset(vfExtendedCompositeCunningham1, 0, nSieveExtensions * nCandidatesBytes); memset(vfExtendedCompositeCunningham2, 0, nSieveExtensions * nCandidatesBytes); - nChainLength = TargetGetLength(nBits); - nSieveLayers = nChainLength + nSieveExtensions; - - // Process only a set percentage of the primes - // Most composites are still found - const unsigned int nTotalPrimes = vPrimes.size(); - nPrimes = (uint64)nTotalPrimes * nSievePercentage / 100; - } + memset(vCunningham1Multipliers, 0xFF, nMultiplierBytes); + memset(vCunningham2Multipliers, 0xFF, nMultiplierBytes); - ~CSieveOfEratosthenes() - { - free(vfCandidates); - free(vfCompositeBiTwin); - free(vfCompositeCunningham1); - free(vfCompositeCunningham2); - free(vfExtendedCandidates); - free(vfExtendedCompositeBiTwin); - free(vfExtendedCompositeCunningham1); - free(vfExtendedCompositeCunningham2); + fIsReady = true; + fIsDepleted = false; } // Get total number of candidates for power test @@ -249,12 +600,20 @@ class CSieveOfEratosthenes return nCandidateCount; unsigned int nCandidates = 0; -#ifdef __GNUC__ +#ifdef USE_GCC_BUILTINS +# ifdef USE_64BIT + for (unsigned int i = 0; i < nCandidatesWords; i++) + nCandidates += __builtin_popcountll(vfCandidates[i]); + for (unsigned int j = 0; j < nSieveExtensions; j++) + for (unsigned int i = 0; i < nCandidatesWords; i++) + nCandidates += __builtin_popcountll(vfExtendedCandidates[j * nCandidatesWords + i]); +# else for (unsigned int i = 0; i < nCandidatesWords; i++) - nCandidates += __builtin_popcountl(vfCandidates[i]); + nCandidates += __builtin_popcount(vfCandidates[i]); for (unsigned int j = 0; j < nSieveExtensions; j++) - for (unsigned int i = nCandidatesWords / 2; i < nCandidatesWords; i++) - nCandidates += __builtin_popcountl(vfExtendedCandidates[j * nCandidatesWords + i]); + for (unsigned int i = 0; i < nCandidatesWords; i++) + nCandidates += __builtin_popcount(vfExtendedCandidates[j * nCandidatesWords + i]); +# endif #else for (unsigned int i = 0; i < nCandidatesWords; i++) { @@ -267,7 +626,7 @@ class CSieveOfEratosthenes } for (unsigned int j = 0; j < nSieveExtensions; j++) { - for (unsigned int i = nCandidatesWords / 2; i < nCandidatesWords; i++) + for (unsigned int i = 0; i < nCandidatesWords; i++) { sieve_word_t lBits = vfExtendedCandidates[j * nCandidatesWords + i]; for (unsigned int j = 0; j < nWordBits; j++) @@ -291,39 +650,42 @@ class CSieveOfEratosthenes sieve_word_t *vfActiveCandidates; sieve_word_t *vfActiveCompositeTWN; sieve_word_t *vfActiveCompositeCC1; + sieve_word_t *vfActiveCompositeCC2; + const sieve_word_t nMaxWord = (nSieveSize + nWordBits - 1) / nWordBits; + const unsigned int _nSieveSize = nSieveSize; if (fCandidateIsExtended) { - vfActiveCandidates = vfExtendedCandidates + nCandidateActiveExtension * nCandidatesWords; - vfActiveCompositeTWN = vfExtendedCompositeBiTwin + nCandidateActiveExtension * nCandidatesWords; - vfActiveCompositeCC1 = vfExtendedCompositeCunningham1 + nCandidateActiveExtension * nCandidatesWords; + const sieve_word_t nExtOffset = nCandidateActiveExtension * nCandidatesWords; + vfActiveCandidates = vfExtendedCandidates + nExtOffset; + vfActiveCompositeTWN = vfExtendedCompositeBiTwin + nExtOffset; + vfActiveCompositeCC1 = vfExtendedCompositeCunningham1 + nExtOffset; + vfActiveCompositeCC2 = vfExtendedCompositeCunningham2 + nExtOffset; } else { vfActiveCandidates = vfCandidates; vfActiveCompositeTWN = vfCompositeBiTwin; vfActiveCompositeCC1 = vfCompositeCunningham1; + vfActiveCompositeCC2 = vfCompositeCunningham2; } - // Acquire the current word from the bitmap - sieve_word_t lBits = vfActiveCandidates[GetWordNum(nCandidateIndex)]; - loop { nCandidateIndex++; - if (nCandidateIndex >= nSieveSize) + if (unlikely(nCandidateIndex >= _nSieveSize)) { // Check if extensions are available if (!fCandidateIsExtended && nSieveExtensions > 0) { fCandidateIsExtended = true; nCandidateActiveExtension = 0; - nCandidateIndex = nSieveSize / 2; + nCandidateIndex = 0; } else if (fCandidateIsExtended && nCandidateActiveExtension + 1 < nSieveExtensions) { nCandidateActiveExtension++; - nCandidateIndex = nSieveSize / 2; + nCandidateIndex = 0; } else { @@ -332,51 +694,57 @@ class CSieveOfEratosthenes nCandidateActiveExtension = 0; nCandidateIndex = 0; nCandidateMultiplier = 0; + fIsDepleted = true; return false; } // Fix the pointers if (fCandidateIsExtended) { - vfActiveCandidates = vfExtendedCandidates + nCandidateActiveExtension * nCandidatesWords; - vfActiveCompositeTWN = vfExtendedCompositeBiTwin + nCandidateActiveExtension * nCandidatesWords; - vfActiveCompositeCC1 = vfExtendedCompositeCunningham1 + nCandidateActiveExtension * nCandidatesWords; + const sieve_word_t nExtOffset = nCandidateActiveExtension * nCandidatesWords; + vfActiveCandidates = vfExtendedCandidates + nExtOffset; + vfActiveCompositeTWN = vfExtendedCompositeBiTwin + nExtOffset; + vfActiveCompositeCC1 = vfExtendedCompositeCunningham1 + nExtOffset; + vfActiveCompositeCC2 = vfExtendedCompositeCunningham2 + nExtOffset; } else { vfActiveCandidates = vfCandidates; vfActiveCompositeTWN = vfCompositeBiTwin; vfActiveCompositeCC1 = vfCompositeCunningham1; + vfActiveCompositeCC2 = vfCompositeCunningham2; } } - if (nCandidateIndex % nWordBits == 0) + if (unlikely(nCandidateIndex % nWordBits == 0)) { - // Update the current word - lBits = vfActiveCandidates[GetWordNum(nCandidateIndex)]; - - // Check if any bits are set - if (lBits == 0) + sieve_word_t nWord = nCandidateIndex / nWordBits; + // Fast loop to skip empty words + for (; likely(nWord < nMaxWord); nWord++) { - // Skip an entire word - nCandidateIndex += nWordBits - 1; - continue; + if (vfActiveCandidates[nWord] != 0) + break; } + nCandidateIndex = nWord * nWordBits; + if (nCandidateIndex >= _nSieveSize) + continue; } - if (lBits & GetBitMask(nCandidateIndex)) + if (unlikely((vfActiveCandidates[GetWordNum(nCandidateIndex)] & GetBitMask(nCandidateIndex)) != 0)) { if (fCandidateIsExtended) - nCandidateMultiplier = nCandidateIndex * (2 << nCandidateActiveExtension); + nCandidateMultiplier = (2 * nCandidateIndex + 1) * (2 << nCandidateActiveExtension); else - nCandidateMultiplier = nCandidateIndex; + nCandidateMultiplier = 2 * nCandidateIndex + 1; nVariableMultiplier = nCandidateMultiplier; if (~vfActiveCompositeTWN[GetWordNum(nCandidateIndex)] & GetBitMask(nCandidateIndex)) nCandidateType = PRIME_CHAIN_BI_TWIN; else if (~vfActiveCompositeCC1[GetWordNum(nCandidateIndex)] & GetBitMask(nCandidateIndex)) nCandidateType = PRIME_CHAIN_CUNNINGHAM1; - else + else if (~vfActiveCompositeCC2[GetWordNum(nCandidateIndex)] & GetBitMask(nCandidateIndex)) nCandidateType = PRIME_CHAIN_CUNNINGHAM2; + else + nCandidateType = 0; // unknown return true; } } @@ -390,9 +758,11 @@ class CSieveOfEratosthenes // True - weaved another prime; nComposite - number of composites removed // False - sieve already completed bool Weave(); -}; -static const unsigned int nPrimorialHashFactor = 7; + bool IsReady() { return fIsReady; } + bool IsDepleted() { return fIsDepleted; } + void Deplete() { fIsDepleted = true; } +}; inline void mpz_set_uint256(mpz_t r, uint256& u) { diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index b604fd0f..4a1ddde9 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -31,10 +31,12 @@ #define _BITCOIN_QT_PLUGINS_INCLUDED #define __INSURE__ #include +#ifndef BITCOIN_QT_NO_CODECS Q_IMPORT_PLUGIN(qcncodecs) Q_IMPORT_PLUGIN(qjpcodecs) Q_IMPORT_PLUGIN(qtwcodecs) Q_IMPORT_PLUGIN(qkrcodecs) +#endif Q_IMPORT_PLUGIN(qtaccessiblewidgets) #endif @@ -153,9 +155,9 @@ int main(int argc, char *argv[]) QApplication::setOrganizationName("Datacoin"); QApplication::setOrganizationDomain("datacoin has no domain yet"); if(GetBoolArg("-testnet")) // Separate UI settings for testnet - QApplication::setApplicationName("Datacoin-Qt-testnet"); + QApplication::setApplicationName("Datacoin-HP-Qt-testnet"); else - QApplication::setApplicationName("Datacoin-Qt"); + QApplication::setApplicationName("Datacoin-HP-Qt"); // ... then GUI settings: OptionsModel optionsModel; diff --git a/src/qt/bitcoinaddressvalidator.h b/src/qt/bitcoinaddressvalidator.h index 2b6a5936..b7f4dfee 100644 --- a/src/qt/bitcoinaddressvalidator.h +++ b/src/qt/bitcoinaddressvalidator.h @@ -3,8 +3,8 @@ #include -/** Base48 entry widget validator. - Corrects near-miss characters and refuses characters that are no part of base48. +/** Base58 entry widget validator. + Corrects near-miss characters and refuses characters that are not part of base58. */ class BitcoinAddressValidator : public QValidator { diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a0ef1465..c40a8d5c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -68,7 +68,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent) : prevBlocks(0) { restoreWindowGeometry(); - setWindowTitle(tr("Datacoin") + " - " + tr("Wallet")); + setWindowTitle(tr("Datacoin High Performance") + " - " + tr("Wallet")); #ifndef Q_OS_MAC QApplication::setWindowIcon(QIcon(":icons/datacoin")); setWindowIcon(QIcon(":icons/datacoin")); @@ -598,7 +598,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret) { - QString strTitle = tr("Datacoin"); // default title + QString strTitle = tr("Datacoin High Performance"); // default title // Default to information icon int nMBoxIcon = QMessageBox::Information; int nNotifyIcon = Notificator::Information; diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index daa9a5e7..baf4ee17 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -91,7 +91,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"), QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"), QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat"), -QT_TRANSLATE_NOOP("bitcoin-core", "Datacoin version"), +QT_TRANSLATE_NOOP("bitcoin-core", "Datacoin High Performance version"), QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"), diff --git a/src/qt/forms/aboutdialog.ui b/src/qt/forms/aboutdialog.ui index 719aad9d..e4051d2d 100644 --- a/src/qt/forms/aboutdialog.ui +++ b/src/qt/forms/aboutdialog.ui @@ -145,7 +145,12 @@ This is experimental software. Distributed under conditional MIT/X11 software license, see the accompanying file COPYING. -This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. This product includes the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. true diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index d1962fa7..d0ddbd48 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -421,7 +421,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; } HelpMessageBox::HelpMessageBox(QWidget *parent) : QMessageBox(parent) { - header = tr("Datacoin-Qt") + " " + tr("version") + " " + + header = tr("Datacoin High Performance-Qt") + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion()) + "\n\n" + tr("Usage:") + "\n" + " datacoin-qt [" + tr("command-line options") + "] " + "\n"; @@ -433,7 +433,7 @@ HelpMessageBox::HelpMessageBox(QWidget *parent) : " -min " + tr("Start minimized") + "\n" + " -splash " + tr("Show splash screen on startup (default: 1)") + "\n"; - setWindowTitle(tr("Datacoin-Qt")); + setWindowTitle(tr("Datacoin High Performance-Qt")); setTextFormat(Qt::PlainText); // setMinimumWidth is ignored for QMessageBox so put in non-breaking spaces to make it wider. setText(header + QString(QChar(0x2003)).repeated(50)); diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts index c580472b..4052f0d0 100644 --- a/src/qt/locale/bitcoin_af_ZA.ts +++ b/src/qt/locale/bitcoin_af_ZA.ts @@ -243,7 +243,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt @@ -2178,8 +2178,8 @@ Address: %4 datacoin-core - Datacoin version - Datacoin weergawe + Datacoin High Performance version + Datacoin High Performance weergawe diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index 543e0d10..c46506ae 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -243,7 +243,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt @@ -2178,7 +2178,7 @@ Address: %4 datacoin-core - Datacoin version + Datacoin High Performance version diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index 1ec37100..e08da996 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -248,7 +248,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! @@ -752,7 +752,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt @@ -2183,8 +2183,8 @@ Address: %4 datacoin-core - Datacoin version - Биткоин версия + Datacoin High Performance version + Datacoin High Performance версия diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts index 333043c8..5765e69d 100644 --- a/src/qt/locale/bitcoin_bs.ts +++ b/src/qt/locale/bitcoin_bs.ts @@ -243,7 +243,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt @@ -2178,7 +2178,7 @@ Address: %4 datacoin-core - Datacoin version + Datacoin High Performance version diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index c4b08394..e393a9ac 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -243,7 +243,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt @@ -2178,7 +2178,7 @@ Address: %4 datacoin-core - Datacoin version + Datacoin High Performance version diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index 7c8a428f..dc99a6be 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -243,8 +243,8 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! - Advertència: Si encripteu el vostre moneder i perdeu la constrasenya, <b>PERDREU TOTS ELS VOSTRES DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! + Advertència: Si encripteu el vostre moneder i perdeu la constrasenya, <b>PERDREU TOTS ELS VOSTRES PRIMECOINS</b>! @@ -747,8 +747,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt @@ -2178,8 +2178,8 @@ Address: %4 datacoin-core - Datacoin version - Versió de Datacoin + Datacoin High Performance version + Versió de Datacoin High Performance diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 7f9a4bae..88e2dbc1 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -756,8 +756,8 @@ Adresa: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts index 28aa6890..882d838f 100644 --- a/src/qt/locale/bitcoin_cy.ts +++ b/src/qt/locale/bitcoin_cy.ts @@ -243,7 +243,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt @@ -2178,7 +2178,7 @@ Address: %4 datacoin-core - Datacoin version + Datacoin High Performance version diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 36cb7ad7..c6627825 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -248,8 +248,8 @@ Produktet indeholder software som er udviklet af OpenSSL Project til brug i Open - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! - Advarsel: Hvis du krypterer din tegnebog og mister din adgangskode, vil du <b>MISTE ALLE DINE DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! + Advarsel: Hvis du krypterer din tegnebog og mister din adgangskode, vil du <b>MISTE ALLE DINE PRIMECOINS</b>! @@ -756,8 +756,8 @@ Adresse: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt @@ -2187,8 +2187,8 @@ Adresse: %4 datacoin-core - Datacoin version - Datacoin-version + Datacoin High Performance version + Datacoin High Performance version diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index 6e34029a..35a4a1d8 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -248,7 +248,7 @@ Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im Open - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! Warnung: Wenn Sie Ihre Brieftasche verschlüsseln und Ihre Passphrase verlieren, werden Sie <b>alle Ihre Datacoins verlieren</b>! @@ -755,8 +755,8 @@ Adresse: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt @@ -2186,8 +2186,8 @@ Adresse: %4 datacoin-core - Datacoin version - Datacoin-Version + Datacoin High Performance version + Datacoin High Performance Version diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts index 29cecf95..54fb6d65 100644 --- a/src/qt/locale/bitcoin_el_GR.ts +++ b/src/qt/locale/bitcoin_el_GR.ts @@ -759,7 +759,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt bitcoin-qt diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 6b82999d..58441e15 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -770,8 +770,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts index 4098cfd1..c59c21f0 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -747,8 +747,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index c8520ebb..e308a331 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -759,8 +759,8 @@ Dirección: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index 6f9c6223..2de06c6c 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -758,7 +758,7 @@ Dirección: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index 297b7e5b..547e928b 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -755,8 +755,8 @@ Aadress: %4⏎ - Datacoin-Qt - Datacoini-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt @@ -2934,4 +2934,4 @@ If the file does not exist, create it with owner-readable-only file permissions. Kui seda faili ei ole, loo see ainult-omanikule-lugemiseks faili õigustes. - \ No newline at end of file + diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts index 311f0af4..c247e4f1 100644 --- a/src/qt/locale/bitcoin_eu_ES.ts +++ b/src/qt/locale/bitcoin_eu_ES.ts @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index e04d8e15..6ac1a3d3 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -751,8 +751,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts index 029149ed..fb8538ae 100644 --- a/src/qt/locale/bitcoin_fa_IR.ts +++ b/src/qt/locale/bitcoin_fa_IR.ts @@ -749,7 +749,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index 22e7579a..2491d415 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -756,8 +756,8 @@ Osoite: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index 6683a3f2..5647a700 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -756,8 +756,8 @@ Adresse : %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts index cb4c3a3a..0d845b6b 100644 --- a/src/qt/locale/bitcoin_fr_CA.ts +++ b/src/qt/locale/bitcoin_fr_CA.ts @@ -752,7 +752,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_gu_IN.ts b/src/qt/locale/bitcoin_gu_IN.ts index 7c21f7b1..c7c868e5 100644 --- a/src/qt/locale/bitcoin_gu_IN.ts +++ b/src/qt/locale/bitcoin_gu_IN.ts @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 45055d2b..fe8a613e 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.ts @@ -755,8 +755,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts index a165c58c..063b2b36 100644 --- a/src/qt/locale/bitcoin_hi_IN.ts +++ b/src/qt/locale/bitcoin_hi_IN.ts @@ -751,7 +751,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt बीटकोइन-Qt diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index d9ad6477..5ca9a9dd 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -751,7 +751,7 @@ Adresa:%4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index e062e9de..8f04dc5a 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -755,7 +755,7 @@ Cím: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index fcc4bee0..d51024aa 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -757,8 +757,8 @@ Indirizzo: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index 87355a14..446b7aa4 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index aeaa7a95..36fd52f6 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -755,8 +755,8 @@ Inscriptio: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index db0c8fc8..77042c8c 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -754,8 +754,8 @@ Adresas: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts index 743d21c6..259dffe5 100644 --- a/src/qt/locale/bitcoin_lv_LV.ts +++ b/src/qt/locale/bitcoin_lv_LV.ts @@ -751,8 +751,8 @@ Adrese: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 1fb5e0e0..1f24a0b2 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -756,8 +756,8 @@ Adresse: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 4890b9e6..98fa2136 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -756,8 +756,8 @@ Adres: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index 64de1092..c5bd3cad 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -756,8 +756,8 @@ Adres: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index bae936bf..bd189585 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -755,8 +755,8 @@ Endereço: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index 52c7e42b..30590f22 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -756,8 +756,8 @@ Endereço: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts index cbc60985..2bd2937e 100644 --- a/src/qt/locale/bitcoin_ro_RO.ts +++ b/src/qt/locale/bitcoin_ro_RO.ts @@ -747,8 +747,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index 2fd20652..05e8af1d 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -756,8 +756,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index 99a56116..d138d56c 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -750,7 +750,7 @@ Adresa: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index 4987e47d..f826db59 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index 58209a19..1f26aa75 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -757,8 +757,8 @@ Adress: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts index e8bbe020..4c41edf4 100644 --- a/src/qt/locale/bitcoin_th_TH.ts +++ b/src/qt/locale/bitcoin_th_TH.ts @@ -747,7 +747,7 @@ Address: %4 - Datacoin-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index b3a38683..12ea269f 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -756,8 +756,8 @@ Adres: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index aa0f3bda..4bd6643e 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -248,7 +248,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! УВАГА: Якщо ви зашифруєте гаманець і забудете пароль, ви <b>ВТРАТИТЕ ВСІ СВОЇ БІТКОІНИ</b>! @@ -756,8 +756,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt @@ -2187,8 +2187,8 @@ Address: %4 datacoin-core - Datacoin version - Версія + Datacoin High Performance version + diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 3bdd3a83..c8058baf 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -248,7 +248,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! 警告:如果您加密了您的钱包,但是忘记了密码,你将会<b>丢失所有的比特币</b>! @@ -756,8 +756,8 @@ Address: %4 - Datacoin-Qt - Datacoin-Qt + Datacoin High Performance-Qt + @@ -2188,8 +2188,8 @@ Address: %4 datacoin-core - Datacoin version - 比特币版本 + Datacoin High Performance version + diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index e8d95b2e..26205f33 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -248,7 +248,7 @@ This product includes software developed by the OpenSSL Project for use in the O - Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DATACOINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR PRIMECOINS</b>! 警告: 如果將錢包加密後忘記密碼, 你會<b>失去其中所有的位元幣</b>! @@ -755,8 +755,8 @@ Address: %4 - Datacoin-Qt - 位元幣-Qt + Datacoin High Performance-Qt + Datacoin High Performance-Qt @@ -2187,8 +2187,8 @@ Address: %4 datacoin-core - Datacoin version - 位元幣版本 + Datacoin High Performance version + diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index b6ea8e1d..02117536 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -52,6 +52,8 @@ - (void)handleDockClickEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAp this->m_dummyWidget = new QWidget(); this->m_dockMenu = new QMenu(this->m_dummyWidget); qt_mac_set_dock_menu(this->m_dockMenu); + this->setMainWindow(NULL); + [pool release]; } @@ -100,8 +102,11 @@ - (void)handleDockClickEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAp void MacDockIconHandler::handleDockIconClickEvent() { - this->mainWindow->activateWindow(); - this->mainWindow->show(); + if (this->mainWindow) + { + this->mainWindow->activateWindow(); + this->mainWindow->show(); + } emit this->dockIconClicked(); } diff --git a/src/qt/res/bitcoin-qt.rc b/src/qt/res/bitcoin-qt.rc index ce1af0a7..1405e5c4 100644 --- a/src/qt/res/bitcoin-qt.rc +++ b/src/qt/res/bitcoin-qt.rc @@ -21,13 +21,13 @@ BEGIN BLOCK "040904E4" // U.S. English - multilingual (hex) BEGIN VALUE "CompanyName", "Datacoin" - VALUE "FileDescription", "Datacoin-Qt (OSS GUI client for Datacoin)" + VALUE "FileDescription", "Datacoin High Performance-Qt" VALUE "FileVersion", VER_FILEVERSION_STR - VALUE "InternalName", "datacoin-qt" + VALUE "InternalName", "datacoin-hp-qt" VALUE "LegalCopyright", COPYRIGHT_STR VALUE "LegalTrademarks1", "Distributed under conditional MIT/X11 software license, see the accompanying file COPYING." VALUE "OriginalFilename", "datacoin-qt.exe" - VALUE "ProductName", "Datacoin-Qt" + VALUE "ProductName", "Datacoin High Performance-Qt" VALUE "ProductVersion", VER_PRODUCTVERSION_STR END END diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 01e0d061..8d9b7c84 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -170,7 +170,7 @@ void SendCoinsDialog::clear() // Remove entries until only one left while(ui->entries->count()) { - delete ui->entries->takeAt(0)->widget(); + ui->entries->takeAt(0)->widget()->deleteLater(); } addEntry(); @@ -226,7 +226,7 @@ void SendCoinsDialog::updateRemoveEnabled() void SendCoinsDialog::removeEntry(SendCoinsEntry* entry) { - delete entry; + entry->deleteLater(); updateRemoveEnabled(); } diff --git a/src/qt/walletstack.cpp b/src/qt/walletstack.cpp index 9e3060e8..3576d55c 100644 --- a/src/qt/walletstack.cpp +++ b/src/qt/walletstack.cpp @@ -13,6 +13,7 @@ WalletStack::WalletStack(QWidget *parent) : QStackedWidget(parent), + gui(0), clientModel(0), bOutOfSync(true) { @@ -35,6 +36,10 @@ bool WalletStack::addWallet(const QString& name, WalletModel *walletModel) walletView->showOutOfSyncWarning(bOutOfSync); addWidget(walletView); mapWalletViews[name] = walletView; + + // Ensure a walletView is able to show the main window + connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized())); + return true; } diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 6d44c174..1de145c3 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -203,6 +203,7 @@ bool WalletView::handleURI(const QString& strURI) if (sendCoinsPage->handleURI(strURI)) { gotoSendCoinsPage(); + emit showNormalIfMinimized(); return true; } else diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 6bcd70ba..6ad5180d 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -99,6 +99,10 @@ public slots: void unlockWallet(); void setEncryptionStatus(); + +signals: + /** Signal that we want to show the main window */ + void showNormalIfMinimized(); }; #endif // WALLETVIEW_H diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 9b80e0b2..4a52a4c9 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -50,31 +50,59 @@ Value setgenerate(const Array& params, bool fHelp) } -Value getsievepercentage(const Array& params, bool fHelp) +Value getsievesize(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "getsievepercentage\n" - "Returns the current sieve percentage used by the mining algorithm."); + "getsievesize\n" + "Returns the current sieve size used by the mining algorithm."); - return (boost::int64_t)nSievePercentage; + return (boost::int64_t)nSieveSize; } -Value setsievepercentage(const Array& params, bool fHelp) +Value setsievesize(const Array& params, bool fHelp) { if (fHelp || params.size() < 1) throw runtime_error( - "setsievepercentage \n" - " determines how many rounds the candidate multiplier sieve runs."); + "setsievesize \n" + " determines how many numbers are sieved at one time."); - unsigned int nPercentage = nDefaultSievePercentage; + unsigned int nSize = nDefaultSieveSize; if (params.size() > 0) - nPercentage = params[0].get_int(); + nSize = params[0].get_int(); - nPercentage = std::max(std::min(nPercentage, nMaxSievePercentage), nMinSievePercentage); + nSize = std::max(std::min(nSize, nMaxSieveSize), nMinSieveSize); + nSieveSize = nSize; + return Value::null; +} + + +Value getsievefilterprimes(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getsievefilterprimes\n" + "Returns the current number of primes that are filtered out by the sieve."); + + return (boost::int64_t)nSieveFilterPrimes; +} + + +Value setsievefilterprimes(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1) + throw runtime_error( + "setsievefilterprimes \n" + " determines how many primes are filtered out by the sieve."); + + unsigned int nPrimes = nDefaultSieveFilterPrimes; + if (params.size() > 0) + nPrimes = params[0].get_int(); + + nPrimes = std::max(std::min(nPrimes, nMaxSieveFilterPrimes), nMinSieveFilterPrimes); - nSievePercentage = nPercentage; + nSieveFilterPrimes = nPrimes; return Value::null; } @@ -119,17 +147,6 @@ Value getprimespersec(const Array& params, bool fHelp) } -Value getchainspermin(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getchainspermin\n" - "Returns a recent chains per second performance measurement while generating."); - - return (boost::int64_t)dChainsPerMinute; -} - - extern Value getdifficulty(const Array& params, bool fHelp); @@ -142,7 +159,7 @@ Value getmininginfo(const Array& params, bool fHelp) Object obj; obj.push_back(Pair("blocks", (int)nBestHeight)); - obj.push_back(Pair("chainspermin", getchainspermin(params, false))); + obj.push_back(Pair("blocksperday", dBlocksPerDay)); obj.push_back(Pair("chainsperday", dChainsPerDay)); obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx)); @@ -150,10 +167,9 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("errors", GetWarnings("statusbar"))); obj.push_back(Pair("generate", GetBoolArg("-gen"))); obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); - obj.push_back(Pair("primespersec", getprimespersec(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("sieveextensions",(int)nSieveExtensions)); - obj.push_back(Pair("sievepercentage",(int)nSievePercentage)); + obj.push_back(Pair("sievefilterprimes",(int)nSieveFilterPrimes)); obj.push_back(Pair("sievesize", (int)nSieveSize)); obj.push_back(Pair("testnet", fTestNet)); return obj; diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 6d97c298..71c2be93 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -59,7 +59,10 @@ Value getpeerinfo(const Array& params, bool fHelp) obj.push_back(Pair("bytesrecv", (boost::int64_t)stats.nRecvBytes)); obj.push_back(Pair("conntime", (boost::int64_t)stats.nTimeConnected)); obj.push_back(Pair("version", stats.nVersion)); - obj.push_back(Pair("subver", stats.strSubVer)); + // Use the sanitized form of subver here, to avoid tricksy remote peers from + // corrupting or modifiying the JSON output by putting special characters in + // their ver message. + obj.push_back(Pair("subver", stats.cleanSubVer)); obj.push_back(Pair("inbound", stats.fInbound)); obj.push_back(Pair("startingheight", stats.nStartingHeight)); obj.push_back(Pair("banscore", stats.nMisbehavior)); diff --git a/src/serialize.h b/src/serialize.h index e3d9939b..eac4e06c 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -895,19 +895,6 @@ class CDataStream iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } - void insert(iterator it, const_iterator first, const_iterator last) - { - assert(last - first >= 0); - if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - void insert(iterator it, std::vector::const_iterator first, std::vector::const_iterator last) { assert(last - first >= 0); diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index b1e98f65..2ee64755 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -16,10 +16,10 @@ #include // Tests this internal-to-main.cpp method: -extern bool AddOrphanTx(const CDataStream& vMsg); +extern bool AddOrphanTx(const CTransaction& tx); extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); -extern std::map mapOrphanTransactions; -extern std::map > mapOrphanTransactionsByPrev; +extern std::map mapOrphanTransactions; +extern std::map > mapOrphanTransactionsByPrev; CService ip(uint32_t i) { @@ -133,14 +133,11 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits) CTransaction RandomOrphan() { - std::map::iterator it; + std::map::iterator it; it = mapOrphanTransactions.lower_bound(GetRandHash()); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); - const CDataStream* pvMsg = it->second; - CTransaction tx; - CDataStream(*pvMsg) >> tx; - return tx; + return it->second; } BOOST_AUTO_TEST_CASE(DoS_mapOrphans) @@ -162,9 +159,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + AddOrphanTx(tx); } // ... and 50 that depend on other orphans: @@ -181,9 +176,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); SignSignature(keystore, txPrev, tx, 0); - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + AddOrphanTx(tx); } // This really-big orphan should be ignored: @@ -207,9 +200,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) for (unsigned int j = 1; j < tx.vin.size(); j++) tx.vin[j].scriptSig = tx.vin[0].scriptSig; - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - BOOST_CHECK(!AddOrphanTx(ds)); + BOOST_CHECK(!AddOrphanTx(tx)); } // Test LimitOrphanTxSize() function: @@ -246,9 +237,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); - CDataStream ds(SER_DISK, CLIENT_VERSION); - ds << tx; - AddOrphanTx(ds); + AddOrphanTx(tx); } // Create a transaction that depends on orphans: diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 1b0ccad5..e2247767 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -263,28 +263,10 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) { - // Expected results for the determinstic seed. - const uint32_t exp_vals[11] = { 91632771U,1889679809U,3842137544U,3256031132U, - 1761911779U, 489223532U,2692793790U,2737472863U, - 2796262275U,1309899767U,840571781U}; - // Expected 0s in rand()%(idx+2) for the determinstic seed. - const int exp_count[9] = {5013,3346,2415,1972,1644,1386,1176,1096,1009}; int i; int count=0; - seed_insecure_rand(); - - //Does the non-determistic rand give us results that look too like the determinstic one? - for (i=0;i<10;i++) - { - int match = 0; - uint32_t rval = insecure_rand(); - for (int j=0;j<11;j++)match |= rval==exp_vals[j]; - count += match; - } - // sum(binomial(10,i)*(11/(2^32))^i*(1-(11/(2^32)))^(10-i),i,0,4) ~= 1-1/2^134.73 - // So _very_ unlikely to throw a false failure here. - BOOST_CHECK(count<=4); + seed_insecure_rand(true); for (int mod=2;mod<11;mod++) { @@ -307,20 +289,17 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) BOOST_CHECK(count<=10000/mod+err); BOOST_CHECK(count>=10000/mod-err); } +} - seed_insecure_rand(true); - - for (i=0;i<11;i++) - { - BOOST_CHECK_EQUAL(insecure_rand(),exp_vals[i]); - } - - for (int mod=2;mod<11;mod++) - { - count = 0; - for (i=0;i<10000;i++) count += insecure_rand()%mod==0; - BOOST_CHECK_EQUAL(count,exp_count[mod-2]); - } +BOOST_AUTO_TEST_CASE(util_TimingResistantEqual) +{ + BOOST_CHECK(TimingResistantEqual(std::string(""), std::string(""))); + BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string(""))); + BOOST_CHECK(!TimingResistantEqual(std::string(""), std::string("abc"))); + BOOST_CHECK(!TimingResistantEqual(std::string("a"), std::string("aa"))); + BOOST_CHECK(!TimingResistantEqual(std::string("aa"), std::string("a"))); + BOOST_CHECK(TimingResistantEqual(std::string("abc"), std::string("abc"))); + BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("aba"))); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util.cpp b/src/util.cpp index 21f31735..bfb66a7a 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -455,6 +455,19 @@ bool ParseMoney(const char* pszIn, int64& nRet) return true; } +// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything +// even possibly remotely dangerous like & or > +static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@-()"); +string SanitizeString(const string& str) +{ + string strResult; + for (std::string::size_type i = 0; i < str.size(); i++) + { + if (safeChars.find(str[i]) != std::string::npos) + strResult.push_back(str[i]); + } + return strResult; +} static const signed char phexdigit[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, @@ -1072,7 +1085,7 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) if (fNetSpecific && GetBoolArg("-testnet", false)) path /= "testnet"; - fs::create_directory(path); + fs::create_directories(path); fCachedPath[fNetSpecific] = true; return path; @@ -1119,6 +1132,7 @@ boost::filesystem::path GetPidFile() return pathPidFile; } +#ifndef WIN32 void CreatePidFile(const boost::filesystem::path &path, pid_t pid) { FILE* file = fopen(path.string().c_str(), "w"); @@ -1128,6 +1142,7 @@ void CreatePidFile(const boost::filesystem::path &path, pid_t pid) fclose(file); } } +#endif bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest) { @@ -1148,6 +1163,8 @@ void FileCommit(FILE *fileout) #else #if defined(__linux__) || defined(__NetBSD__) fdatasync(fileno(fileout)); + #elif defined(__APPLE__) && defined(F_FULLFSYNC) + fcntl(fileno(fileout), F_FULLFSYNC, 0); #else fsync(fileno(fileout)); #endif @@ -1398,6 +1415,8 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const if (!comments.empty()) ss << "(" << boost::algorithm::join(comments, "; ") << ")"; ss << "/"; + ss << "Datacoin:" << FormatVersion(PRIMECOIN_VERSION); + ss << "(" << CLIENT_BUILD << ")/"; return ss.str(); } diff --git a/src/util.h b/src/util.h index f98bdf94..75cafe1c 100644 --- a/src/util.h +++ b/src/util.h @@ -112,7 +112,11 @@ T* alignup(T* p) inline void MilliSleep(int64 n) { -#if BOOST_VERSION >= 105000 +// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50 +// until fixed in 1.52. Use the deprecated sleep method for the broken case. +// See: https://svn.boost.org/trac/boost/ticket/7238 + +#if BOOST_VERSION >= 105000 && (!defined(BOOST_HAS_NANOSLEEP) || BOOST_VERSION >= 105200) boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); #else boost::this_thread::sleep(boost::posix_time::milliseconds(n)); @@ -188,6 +192,7 @@ void ParseString(const std::string& str, char c, std::vector& v); std::string FormatMoney(int64 n, bool fPlus=false); bool ParseMoney(const std::string& str, int64& nRet); bool ParseMoney(const char* pszIn, int64& nRet); +std::string SanitizeString(const std::string& str); std::vector ParseHex(const char* psz); std::vector ParseHex(const std::string& str); bool IsHex(const std::string& str); @@ -212,7 +217,9 @@ boost::filesystem::path GetDefaultDataDir(); const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); boost::filesystem::path GetConfigFile(); boost::filesystem::path GetPidFile(); +#ifndef WIN32 void CreatePidFile(const boost::filesystem::path &path, pid_t pid); +#endif void ReadConfigFile(std::map& mapSettingsRet, std::map >& mapMultiSettingsRet); #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); @@ -438,6 +445,7 @@ static inline uint32_t insecure_rand(void) * @param Deterministic Use a determinstic seed */ void seed_insecure_rand(bool fDeterministic=false); + /** * Timing-attack-resistant comparison. * Takes time proportional to length diff --git a/src/version.cpp b/src/version.cpp index e89474eb..8239f831 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -15,7 +15,7 @@ const std::string CLIENT_NAME("Satoshi"); #define CLIENT_VERSION_SUFFIX "-beta" // Special version string -#define SPECIAL_VERSION_STR "dtc-hp11" +#define SPECIAL_VERSION_STR "dtc-hp14" // The following part of the code determines the CLIENT_BUILD variable. diff --git a/src/version.h b/src/version.h index e0230e06..cefae2c4 100644 --- a/src/version.h +++ b/src/version.h @@ -22,6 +22,12 @@ extern const std::string CLIENT_NAME; extern const std::string CLIENT_BUILD; extern const std::string CLIENT_DATE; +static const int PRIMECOIN_VERSION = + 1000000 * PRIMECOIN_VERSION_MAJOR + + 10000 * PRIMECOIN_VERSION_MINOR + + 100 * PRIMECOIN_VERSION_REVISION + + 1 * PRIMECOIN_VERSION_BUILD; + // // network protocol versioning // diff --git a/src/wallet.cpp b/src/wallet.cpp index d66350c7..d2d64330 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -741,6 +741,10 @@ void CWalletTx::AddSupportingTransactions() { tx = *mapWalletPrev[hash]; } + else + { + continue; + } int nDepth = tx.SetMerkleBranch(); vtxPrev.push_back(tx); @@ -845,7 +849,10 @@ void CWalletTx::RelayWalletTransaction() { BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) { - if (!tx.IsCoinBase()) + // Important: versions of bitcoin before 0.8.6 had a bug that inserted + // empty transactions into the vtxPrev, which will cause the node to be + // banned when retransmitted, hence the check for !tx.vin.empty() + if (!tx.IsCoinBase() && !tx.vin.empty()) if (tx.GetDepthInMainChain() == 0) RelayTransaction((CTransaction)tx, tx.GetHash()); } @@ -1216,9 +1223,10 @@ bool CWallet::CreateTransaction(const vector >& vecSend, } int64 nChange = nValueIn - nValue - nFeeRet; - // if sub-cent change is required, the fee must be raised to at least nMinTxFee - // or until nChange becomes zero - // NOTE: this depends on the exact behaviour of GetMinFee + // The following if statement should be removed once enough miners + // have upgraded to the 0.9 GetMinFee() rules. Until then, this avoids + // creating free transactions that have change outputs less than + // CENT bitcoins. if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) { int64 nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 46b6fc88..7b6f31e1 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -6,6 +6,7 @@ #include "walletdb.h" #include "wallet.h" +#include #include using namespace std;