diff --git a/blockchain.json b/blockchain.json index 83563980..477d6f21 100644 --- a/blockchain.json +++ b/blockchain.json @@ -1,5 +1,5 @@ { - "coinSupply": "10000000000", + "maxBalance": "10000000000", "blockDifficultyInterval": 10, "minBlockTime": 60, "maxBlockTime": 300, @@ -7,156 +7,158 @@ "maxBytesPerUnitFee": 1024, "unitFee": "1.0", "useBrokenMD160ForAddresses": true, - "genesis": { - "assets": [ - { "name": "QORA", "description": "QORA coin", "quantity": 10000000000, "isDivisible": true, "reference": "28u54WRcMfGujtQMZ9dNKFXVqucY7XfPihXAqPFsnx853NPUwfDJy1sMH5boCkahFgjUNYqc5fkduxdBhQTKgUsC" } - ] + "requireGroupForApproval": false, + "defaultGroupId": 0, + "oneNamePerAccount": false, + "genesisInfo": { + "version": 1, "timestamp": "1400247274336", "generatingBalance": "10000000", "transactions": [ - { "recipient": "QUD9y7NZqTtNwvSAUfewd7zKUGoVivVnTW", "amount": "7032468.191" }, - { "recipient": "QVafvKkE5bZTkq8PcXvdaxwuLNN2DGCwYk", "amount": "1716146.084" }, - { "recipient": "QV42QQP7frYWqsVq536g7zSk97fUpf2ZSN", "amount": "5241707.06" }, - { "recipient": "QgkLTm5GkepJpgr53nAgUyYRsvmyHpb2zT", "amount": "854964.0816" }, - { "recipient": "Qc8kN338XQULMBuUa6mTqL5tipvELDhzeZ", "amount": "769467.6734" }, - { "recipient": "QQ81BA75jZcpjQBLZE1qcHrXV8ARC1DEec", "amount": "85496408.16" }, - { "recipient": "QeoSe4DscWX4AFkNBCdm4WS1V7QkUFSQLP", "amount": "854968.3564" }, - { "recipient": "Qdfu3Eh21ZVHNDY1xyNaFqTTEYscSmfSsm", "amount": "85496408.16" }, - { "recipient": "QeDSr4abXKRg9j5hTN3TK9UGuH3umThZ42", "amount": "4445813.224" }, - { "recipient": "QQKDuo1txYB9E2xim79YVR6SQ1ZbJtJtFX", "amount": "47023024.49" }, - { "recipient": "QLeaeGr4CDA95FmeMtFh8okJRMLoq8Cge5", "amount": "170992816.3" }, - { "recipient": "QSwN5oa8ZHWJmc6FeAJ8Xr1SHaEuSahw1J", "amount": "3419856.326" }, - { "recipient": "QWnoGd4a7iXqQmNEpUtCb1x7nWgcya8QbE", "amount": "17056533.43" }, - { "recipient": "QbJqhsJjcy3vkzsJ1kHvgn26pQF3sZEypc", "amount": "42705455.87" }, - { "recipient": "QiBhBcseKzaDnHKyqEJs8z1Xx2rSb9XhBr", "amount": "141069073.5" }, - { "recipient": "QTwYwxBhzivFEWY5yfzyz1pqhJ8XCroKwv", "amount": "85496408.16" }, - { "recipient": "QfikxUU15Dy1oxbcDNEcLeU5cHvbrceq3A", "amount": "17099281.63" }, - { "recipient": "QhdqBmKZeQ3Hg1XUuR5nKtAkw47tuoRi2q", "amount": "12824461.22" }, - { "recipient": "QaVNyTqsTHA6JWMcqntcJf1u9c3qid76xH", "amount": "128244612.2" }, - { "recipient": "QYaDa7bmgo5L9qkcfJKjhPPrQkvGjEoc7y", "amount": "85496408.16" }, - { "recipient": "QQPddvWaYf4pbCyVHEVoyfC72EiaAv4JhT", "amount": "25648922.45" }, - { "recipient": "QSQpTNtTZMwaDuNq56Jz73KHWXaey9JrT1", "amount": "26341443.35" }, - { "recipient": "QVjcFWE6TnGePGJEtbNc1thwD2sgHBLvUV", "amount": "42940528.25" }, - { "recipient": "Qga93mWNqTuJYx6o33vjUpFH7Cn4sxLyoG", "amount": "2564892.245" }, - { "recipient": "QXyHKyQPJnb4ejyTkvS26x9sjWnhTTJ1Uc", "amount": "10259568.98" }, - { "recipient": "QLurSSgJvW7WXHDFSobgfakgqXxjoZzwUH", "amount": "85496408.16" }, - { "recipient": "QadxfiARcsmwzE93wqq82yXFi3ykM2qdtS", "amount": "79118376.11" }, - { "recipient": "QRHhhtz3Cv9RPKB1QBBfkRmRfpXx8vkRa5", "amount": "22435418.54" }, - { "recipient": "Qh8UnEs55n8jcnBaBwVtrTGkFFFBDyrMqH", "amount": "128757590.7" }, - { "recipient": "QhF7Fu3f54CTYA7zBQ223NQEssi2yAbAcx", "amount": "258481290.8" }, - { "recipient": "QPk9VB6tigoifrUYQrw4arBNk7i8HEgsDD", "amount": "128244612.2" }, - { "recipient": "QXWJnEPsdtaLQAEutJFR4ySiMUJCWDzZJX", "amount": "85496408.16" }, - { "recipient": "QVFs42gM4Cixf4Y5vDFvKKxRAamUPMCAVq", "amount": "85496408.16" }, - { "recipient": "Qec5ueWc4rcBrty47GZfFSqvLymxvcycFm", "amount": "129091026.7" }, - { "recipient": "QfYiztbDz1Nb9EMhgHidLycvuPN8HEcHEj", "amount": "128244612.2" }, - { "recipient": "QPdWsZtaZcAKqk2HWVhEVbws4qG5KUTXmg", "amount": "179285967.9" }, - { "recipient": "QVkNs5NcwQpsrCXpWzuMXkMehJr5mkvLVy", "amount": "8558190.456" }, - { "recipient": "Qg19DzyEfyZANx6JLy4GrSGF5LuZ2MLqyZ", "amount": "42748204.08" }, - { "recipient": "Qf3A8L5WJNHt1xZxmayrTp2d5owzdkcxM6", "amount": "50519827.58" }, - { "recipient": "QeKR4W6qkFJGF7Hmu7rSUzTSQiqJzZLXdt", "amount": "10216820.77" }, - { "recipient": "QWg7T5i3uBY3xeBLFTLYYruR15Ln11vwo4", "amount": "170992816.3" }, - { "recipient": "QUYdM5fHECPZxKQQAmoxoQa2aWg8TZYfPw", "amount": "85496408.16" }, - { "recipient": "QjhfEZCgrjUbnLRnWqWxzyYqKQpjjxkuA8", "amount": "86665653.61" }, - { "recipient": "QMA53u3wrzDoxC57CWUJePNdR8FoqinqUS", "amount": "85496408.16" }, - { "recipient": "QSuCp6mB5zNNeJKD62aq2hR9h84ks1WhHf", "amount": "161588211.4" }, - { "recipient": "QS2tCUk7GQefg4zGewwrumxSPmN6fgA7Xc", "amount": "170992816.3" }, - { "recipient": "Qcn6FZRxAgp3japtvjgUkBY6KPfbPZMZtM", "amount": "170992816.3" }, - { "recipient": "QZrmXZkRmjV2GwMt72Rr1ZqHJjv8raDk5J", "amount": "17099281.63" }, - { "recipient": "QeZzwGDfAHa132jb6r4rQHbgJstLuT8QJ3", "amount": "255875360.3" }, - { "recipient": "Qj3L139sMMuFvvjKQDwRnoSgKUnoMhDQs5", "amount": "76946767.34" }, - { "recipient": "QWJvpvbFRZHu7LRbY5MjzvrMBgzJNFYjCX", "amount": "178251461.4" }, - { "recipient": "QRyECqW54ywKVt4kZTEXyRY17aaFUaxzc4", "amount": "8772355.539" }, - { "recipient": "QgpH3K3ArkQTg15xjKqGq3BRgE3aNH9Q2P", "amount": "46766535.26" }, - { "recipient": "QVZ6pxi8e3K3S44zLbnrLSLwSoYT8CWbwV", "amount": "233172022.2" }, - { "recipient": "QNbA69dbnmwqJHLQeS9v63hSLZXXGkmtC6", "amount": "46626632.05" }, - { "recipient": "QgzudSKbcLUeQUhFngotVswDSkbU42dSMr", "amount": "83786479.99" }, - { "recipient": "QfkQ2UzKMBGPwj8Sm31SArjtXoka1ubU3i", "amount": "116345066.7" }, - { "recipient": "QgxHHNwawZeTmQ3i5d9enchi4T9VmzNZ5k", "amount": "155448014.8" }, - { "recipient": "QMNugJWNsLuV4Qmbzdf8r8RMEdXk5PNM69", "amount": "155448014.8" }, - { "recipient": "QVhWuJkCjStNMV4U8PtNM9Qz4PvLAEtVSj", "amount": "101041209.6" }, - { "recipient": "QXjNcckFG9gTr9YbiA3RrRhn3mPJ9zyR4G", "amount": "3108960.297" }, - { "recipient": "QThnuBadmExtxk81vhFKimSzbPaPcuPAdm", "amount": "155448014.8" }, - { "recipient": "QRc6sQthLHjfkmm2BUhu74g33XtkDoB7JP", "amount": "77773983.95" }, - { "recipient": "QcDLhirHkSbR4TLYeShLzHw61B8UGTFusk", "amount": "23317202.22" }, - { "recipient": "QXRnsXE6srHEf2abGh4eogs2mRsmNiuw6V", "amount": "5440680.519" }, - { "recipient": "QRJmEswbDw4x1kwsLyxtMS9533fv5cDvQV", "amount": "3886200.371" }, - { "recipient": "Qg43mCzWmFVwhVfx34g6shXnSU7U7amJNx", "amount": "6217920.593" }, - { "recipient": "QQ9PveFTW64yUcXEE6AxhokWCwhmn8F2TD", "amount": "8549640.816" }, - { "recipient": "QQaxJuTkW5XXn4DhhRekXpdXaWcsxEfCNG", "amount": "3886200.371" }, - { "recipient": "QifWFqW8XWL5mcNxtdr5z1LVC7XUu9tNSK", "amount": "3116732.697" }, - { "recipient": "QavhBKRN4vuyzHNNqcWxjcohRAJNTdTmh4", "amount": "154670774.8" }, - { "recipient": "QMQyR3Hybof8WpQsXPxh19AZFCj4Z4mmke", "amount": "77724007.42" }, - { "recipient": "QbT3GGjp1esTXtowVk2XCtBsKoRB8mkP61", "amount": "77724007.42" }, - { "recipient": "QT13tVMZEtbrgJEsBBcTtnyqGveC7mtqAb", "amount": "23317202.22" }, - { "recipient": "QegT2Ws5YjLQzEZ9YMzWsAZMBE8cAygHZN", "amount": "12606834" }, - { "recipient": "QXoKRBJiJGKwvdA3jkmoUhkM7y6vuMp2pn", "amount": "65117173.41" }, - { "recipient": "QY6SpdBzUev9ziqkmyaxESZSbdKwqGdedn", "amount": "89382608.53" }, - { "recipient": "QeMxyt1nEE7tbFbioc87xhiKb4szx5DsjY", "amount": "15544801.48" }, - { "recipient": "QcTp3THGZvJ42f2mWsQrawGvgBoSHgHZyk", "amount": "39639243.78" }, - { "recipient": "QjSH91mTDN6TeV1naAcfwPhmRogufV4n1u", "amount": "23317202.22" }, - { "recipient": "QiFLELeLm2TFWsnknzje51wMdt3Srkjz8g", "amount": "1554480.148" }, - { "recipient": "QhxtJ3vvhsvVU9x2j5n2R3TXzutfLMUvBR", "amount": "23317202.22" }, - { "recipient": "QUtUSNQfqexZZkaZ2s9LcpqjnTezPTnuAx", "amount": "15544801.48" }, - { "recipient": "Qg6sPLxNMYxjEDGLLaFkkWx6ip3py5fLEt", "amount": "777240.0742" }, - { "recipient": "QeLixskYbdkiAHmhBVMa2Pdi85YPFqw3Ed", "amount": "38862003.71" }, - { "recipient": "Qary17o9qvZ2fifiVC8tF5zoBJm79n18zA", "amount": "3893972.772" }, - { "recipient": "QLvCWDGwzwpR29XgiThMGDX2vxyFW5rFHB", "amount": "8790585.239" }, - { "recipient": "Qgc77fSoAoUSVJfq62GxxTin6dBtU7Y6Hb", "amount": "194310018.5" }, - { "recipient": "QPmPKjwPLCuRei6abuhMtMocxAEeSuLVcv", "amount": "23317202.22" }, - { "recipient": "QcGfZePUN7JHs9WEEkJhXGzALy4JybiS3N", "amount": "194224522.1" }, - { "recipient": "QSeXGwk7eQjR8j7bndJST19qWtM2qnqL1u", "amount": "38862003.71" }, - { "recipient": "QU9i68h71nKTg4gwc5yJHzNRQdQEswP7Kn", "amount": "139592317.3" }, - { "recipient": "QdKrZGCkwXSSeXJhVA1idDXsA4VFtrjPHN", "amount": "15544801.48" }, - { "recipient": "QiYJ2B797xFpWYFu4XWivhGhyPXLU7S5Mr", "amount": "77724007.42" }, - { "recipient": "QWxqtsNXUWSjYns2wdngh4WBSWQzLoQHvx", "amount": "232613963.9" }, - { "recipient": "QTAGfu4FpTZ1bnvnd17YPtB3zabxfWKNeM", "amount": "101041209.6" }, - { "recipient": "QPtRxchgRdwdnoZRwhiAoa77AvVPNSRcQk", "amount": "114254290.9" }, - { "recipient": "QMcfoVc9Jat2pMFLHcuPEPnY6p6uBK6Dk7", "amount": "77724007.42" }, - { "recipient": "Qi84KosdwSWHZX3qz4WcMgqYGutBmj14dd", "amount": "15544801.48" }, - { "recipient": "QjAtcHsgig2tvdGr5tR4oGmRarhuojrAK1", "amount": "2883560.675" }, - { "recipient": "QPJPNLP2NMHu5athB7ydezdTA6zviCV378", "amount": "6373368.608" }, - { "recipient": "QfVLpmLbuUnA1JEe9FmeUAzihoBvqYDp8B", "amount": "15544801.48" }, - { "recipient": "QVVFdy6VLFqAFCb6XSBJLLZybiKgfgDDZV", "amount": "10725913.02" }, - { "recipient": "QVFXyeG1xpAR8Xg3u7oAmW8unueGAfeaKi", "amount": "31221733.78" }, - { "recipient": "QdtQtrM1h3TLtwAGCNyoTrW5HyiPRLhrPq", "amount": "138426457.2" }, - { "recipient": "QMukUMr84Mi2niz6rdhEJMkKJBve7uuRfe", "amount": "116586011.1" }, - { "recipient": "QZR8c7dmfwqGPujebFH1miQToJZ4JQfU1X", "amount": "217938116.8" }, - { "recipient": "QVV5Uu8eCxufTrBtquDKA96d7Kk8S4V7yX", "amount": "40091961.25" }, - { "recipient": "QY9YdgfTEUFvQ2UJszGS63qkwdENkW1PQ5", "amount": "154670774.8" }, - { "recipient": "QNgiswyhVyNJG4UMzvoSf29wDvGZqqs7WG", "amount": "11658601.11" }, - { "recipient": "QabjgFiY34oihNkUcy9hpFjQdCaypCShMe", "amount": "54406805.19" }, - { "recipient": "QionidPRekdshCTRL3c7idWWRAqGYcKaFN", "amount": "7772400.742" }, - { "recipient": "QcJdBJiVgiNBNg6ZwZAiEfYDMi5ZTQaYAa", "amount": "81386689.86" }, - { "recipient": "QNc8XMpPwM1HESwB7kqw8HoQ5sK2miZ2un", "amount": "190423818.2" }, - { "recipient": "QUP1SeaNw7CvCnmDp5ai3onWYwThS4GEpu", "amount": "3886200.371" }, - { "recipient": "QinToqEztNN1TsLdQEuzTHh7vUrEo6JTU2", "amount": "102440241.8" }, - { "recipient": "QcLJYLV4RD4GmPcoNnh7dQrWeYgiiPiqFQ", "amount": "32644083.11" }, - { "recipient": "QdYdYGYfgmMX4jQNWMZqLr81R3HdnuiKkv", "amount": "76169527.27" }, - { "recipient": "Qi62mUW5zfJhgRL8FRmCpjSCCnSKtf76S6", "amount": "76169527.27" }, - { "recipient": "QgFkxqQGkLW6CD95N2zTnT1PPqb9nxWp6b", "amount": "76169527.27" }, - { "recipient": "QfNUBudYsrrq27YqiHGLUg6BtG52W1W1ci", "amount": "15544801.48" }, - { "recipient": "QPSFoexnGoMH7EPdg72dM7SvqA7d4M2cu7", "amount": "37307523.56" }, - { "recipient": "QQxt5WMvoJ2TNScAzcoxHXPnLTeQ43nQ7N", "amount": "21995894.1" }, - { "recipient": "QicpACxck2oDYpzP8iWRQYD4oirCtvjok9", "amount": "93268808.9" }, - { "recipient": "QVTJkdQkTGgqEED9kAsp4BZbYNJqWfhgGw", "amount": "153909079.5" }, - { "recipient": "QQL5vCkhpXnP9F4wqNiBQsNaCocmRcDSUY", "amount": "15512934.64" }, - { "recipient": "QSvEex3p2LaZCVBaCyL8MpYsEpHLwed17r", "amount": "155448014.8" }, - { "recipient": "Qb3Xv96GucQpBG8n96QVFgcs2xXsEWW4CE", "amount": "38862003.71" }, - { "recipient": "QdRua9MqXufALpQFDeYiQDYk3EBGdwGXSx", "amount": "230303229.1" }, - { "recipient": "Qh16Umei91JqiHEVWV8AC6ED9aBqbDYuph", "amount": "231073474" }, - { "recipient": "QMu6HXfZCnwaNmyFjjhWTYAUW7k1x7PoVr", "amount": "231073474" }, - { "recipient": "QgcphUTiVHHfHg8e1LVgg5jujVES7ZDUTr", "amount": "115031531" }, - { "recipient": "QbQk9s4j4EAxAguBhmqA8mdtTct3qGnsrx", "amount": "138348733.2" }, - { "recipient": "QT79PhvBwE6vFzfZ4oh5wdKVsEazZuVJFy", "amount": "6360421.343" } + { "type": "ISSUE_ASSET", "owner": "QLpLzqs4DW1FNJByeJ63qaqw3eAYCxfkjR", "assetName": "QORA", "description": "QORA coin", "quantity": 10000000000, "isDivisible": true, "fee": 0, "reference": "28u54WRcMfGujtQMZ9dNKFXVqucY7XfPihXAqPFsnx853NPUwfDJy1sMH5boCkahFgjUNYqc5fkduxdBhQTKgUsC" }, + { "type": "GENESIS", "recipient": "QUD9y7NZqTtNwvSAUfewd7zKUGoVivVnTW", "amount": "7032468.191" }, + { "type": "GENESIS", "recipient": "QVafvKkE5bZTkq8PcXvdaxwuLNN2DGCwYk", "amount": "1716146.084" }, + { "type": "GENESIS", "recipient": "QV42QQP7frYWqsVq536g7zSk97fUpf2ZSN", "amount": "5241707.06" }, + { "type": "GENESIS", "recipient": "QgkLTm5GkepJpgr53nAgUyYRsvmyHpb2zT", "amount": "854964.0816" }, + { "type": "GENESIS", "recipient": "Qc8kN338XQULMBuUa6mTqL5tipvELDhzeZ", "amount": "769467.6734" }, + { "type": "GENESIS", "recipient": "QQ81BA75jZcpjQBLZE1qcHrXV8ARC1DEec", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "QeoSe4DscWX4AFkNBCdm4WS1V7QkUFSQLP", "amount": "854968.3564" }, + { "type": "GENESIS", "recipient": "Qdfu3Eh21ZVHNDY1xyNaFqTTEYscSmfSsm", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "QeDSr4abXKRg9j5hTN3TK9UGuH3umThZ42", "amount": "4445813.224" }, + { "type": "GENESIS", "recipient": "QQKDuo1txYB9E2xim79YVR6SQ1ZbJtJtFX", "amount": "47023024.49" }, + { "type": "GENESIS", "recipient": "QLeaeGr4CDA95FmeMtFh8okJRMLoq8Cge5", "amount": "170992816.3" }, + { "type": "GENESIS", "recipient": "QSwN5oa8ZHWJmc6FeAJ8Xr1SHaEuSahw1J", "amount": "3419856.326" }, + { "type": "GENESIS", "recipient": "QWnoGd4a7iXqQmNEpUtCb1x7nWgcya8QbE", "amount": "17056533.43" }, + { "type": "GENESIS", "recipient": "QbJqhsJjcy3vkzsJ1kHvgn26pQF3sZEypc", "amount": "42705455.87" }, + { "type": "GENESIS", "recipient": "QiBhBcseKzaDnHKyqEJs8z1Xx2rSb9XhBr", "amount": "141069073.5" }, + { "type": "GENESIS", "recipient": "QTwYwxBhzivFEWY5yfzyz1pqhJ8XCroKwv", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "QfikxUU15Dy1oxbcDNEcLeU5cHvbrceq3A", "amount": "17099281.63" }, + { "type": "GENESIS", "recipient": "QhdqBmKZeQ3Hg1XUuR5nKtAkw47tuoRi2q", "amount": "12824461.22" }, + { "type": "GENESIS", "recipient": "QaVNyTqsTHA6JWMcqntcJf1u9c3qid76xH", "amount": "128244612.2" }, + { "type": "GENESIS", "recipient": "QYaDa7bmgo5L9qkcfJKjhPPrQkvGjEoc7y", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "QQPddvWaYf4pbCyVHEVoyfC72EiaAv4JhT", "amount": "25648922.45" }, + { "type": "GENESIS", "recipient": "QSQpTNtTZMwaDuNq56Jz73KHWXaey9JrT1", "amount": "26341443.35" }, + { "type": "GENESIS", "recipient": "QVjcFWE6TnGePGJEtbNc1thwD2sgHBLvUV", "amount": "42940528.25" }, + { "type": "GENESIS", "recipient": "Qga93mWNqTuJYx6o33vjUpFH7Cn4sxLyoG", "amount": "2564892.245" }, + { "type": "GENESIS", "recipient": "QXyHKyQPJnb4ejyTkvS26x9sjWnhTTJ1Uc", "amount": "10259568.98" }, + { "type": "GENESIS", "recipient": "QLurSSgJvW7WXHDFSobgfakgqXxjoZzwUH", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "QadxfiARcsmwzE93wqq82yXFi3ykM2qdtS", "amount": "79118376.11" }, + { "type": "GENESIS", "recipient": "QRHhhtz3Cv9RPKB1QBBfkRmRfpXx8vkRa5", "amount": "22435418.54" }, + { "type": "GENESIS", "recipient": "Qh8UnEs55n8jcnBaBwVtrTGkFFFBDyrMqH", "amount": "128757590.7" }, + { "type": "GENESIS", "recipient": "QhF7Fu3f54CTYA7zBQ223NQEssi2yAbAcx", "amount": "258481290.8" }, + { "type": "GENESIS", "recipient": "QPk9VB6tigoifrUYQrw4arBNk7i8HEgsDD", "amount": "128244612.2" }, + { "type": "GENESIS", "recipient": "QXWJnEPsdtaLQAEutJFR4ySiMUJCWDzZJX", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "QVFs42gM4Cixf4Y5vDFvKKxRAamUPMCAVq", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "Qec5ueWc4rcBrty47GZfFSqvLymxvcycFm", "amount": "129091026.7" }, + { "type": "GENESIS", "recipient": "QfYiztbDz1Nb9EMhgHidLycvuPN8HEcHEj", "amount": "128244612.2" }, + { "type": "GENESIS", "recipient": "QPdWsZtaZcAKqk2HWVhEVbws4qG5KUTXmg", "amount": "179285967.9" }, + { "type": "GENESIS", "recipient": "QVkNs5NcwQpsrCXpWzuMXkMehJr5mkvLVy", "amount": "8558190.456" }, + { "type": "GENESIS", "recipient": "Qg19DzyEfyZANx6JLy4GrSGF5LuZ2MLqyZ", "amount": "42748204.08" }, + { "type": "GENESIS", "recipient": "Qf3A8L5WJNHt1xZxmayrTp2d5owzdkcxM6", "amount": "50519827.58" }, + { "type": "GENESIS", "recipient": "QeKR4W6qkFJGF7Hmu7rSUzTSQiqJzZLXdt", "amount": "10216820.77" }, + { "type": "GENESIS", "recipient": "QWg7T5i3uBY3xeBLFTLYYruR15Ln11vwo4", "amount": "170992816.3" }, + { "type": "GENESIS", "recipient": "QUYdM5fHECPZxKQQAmoxoQa2aWg8TZYfPw", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "QjhfEZCgrjUbnLRnWqWxzyYqKQpjjxkuA8", "amount": "86665653.61" }, + { "type": "GENESIS", "recipient": "QMA53u3wrzDoxC57CWUJePNdR8FoqinqUS", "amount": "85496408.16" }, + { "type": "GENESIS", "recipient": "QSuCp6mB5zNNeJKD62aq2hR9h84ks1WhHf", "amount": "161588211.4" }, + { "type": "GENESIS", "recipient": "QS2tCUk7GQefg4zGewwrumxSPmN6fgA7Xc", "amount": "170992816.3" }, + { "type": "GENESIS", "recipient": "Qcn6FZRxAgp3japtvjgUkBY6KPfbPZMZtM", "amount": "170992816.3" }, + { "type": "GENESIS", "recipient": "QZrmXZkRmjV2GwMt72Rr1ZqHJjv8raDk5J", "amount": "17099281.63" }, + { "type": "GENESIS", "recipient": "QeZzwGDfAHa132jb6r4rQHbgJstLuT8QJ3", "amount": "255875360.3" }, + { "type": "GENESIS", "recipient": "Qj3L139sMMuFvvjKQDwRnoSgKUnoMhDQs5", "amount": "76946767.34" }, + { "type": "GENESIS", "recipient": "QWJvpvbFRZHu7LRbY5MjzvrMBgzJNFYjCX", "amount": "178251461.4" }, + { "type": "GENESIS", "recipient": "QRyECqW54ywKVt4kZTEXyRY17aaFUaxzc4", "amount": "8772355.539" }, + { "type": "GENESIS", "recipient": "QgpH3K3ArkQTg15xjKqGq3BRgE3aNH9Q2P", "amount": "46766535.26" }, + { "type": "GENESIS", "recipient": "QVZ6pxi8e3K3S44zLbnrLSLwSoYT8CWbwV", "amount": "233172022.2" }, + { "type": "GENESIS", "recipient": "QNbA69dbnmwqJHLQeS9v63hSLZXXGkmtC6", "amount": "46626632.05" }, + { "type": "GENESIS", "recipient": "QgzudSKbcLUeQUhFngotVswDSkbU42dSMr", "amount": "83786479.99" }, + { "type": "GENESIS", "recipient": "QfkQ2UzKMBGPwj8Sm31SArjtXoka1ubU3i", "amount": "116345066.7" }, + { "type": "GENESIS", "recipient": "QgxHHNwawZeTmQ3i5d9enchi4T9VmzNZ5k", "amount": "155448014.8" }, + { "type": "GENESIS", "recipient": "QMNugJWNsLuV4Qmbzdf8r8RMEdXk5PNM69", "amount": "155448014.8" }, + { "type": "GENESIS", "recipient": "QVhWuJkCjStNMV4U8PtNM9Qz4PvLAEtVSj", "amount": "101041209.6" }, + { "type": "GENESIS", "recipient": "QXjNcckFG9gTr9YbiA3RrRhn3mPJ9zyR4G", "amount": "3108960.297" }, + { "type": "GENESIS", "recipient": "QThnuBadmExtxk81vhFKimSzbPaPcuPAdm", "amount": "155448014.8" }, + { "type": "GENESIS", "recipient": "QRc6sQthLHjfkmm2BUhu74g33XtkDoB7JP", "amount": "77773983.95" }, + { "type": "GENESIS", "recipient": "QcDLhirHkSbR4TLYeShLzHw61B8UGTFusk", "amount": "23317202.22" }, + { "type": "GENESIS", "recipient": "QXRnsXE6srHEf2abGh4eogs2mRsmNiuw6V", "amount": "5440680.519" }, + { "type": "GENESIS", "recipient": "QRJmEswbDw4x1kwsLyxtMS9533fv5cDvQV", "amount": "3886200.371" }, + { "type": "GENESIS", "recipient": "Qg43mCzWmFVwhVfx34g6shXnSU7U7amJNx", "amount": "6217920.593" }, + { "type": "GENESIS", "recipient": "QQ9PveFTW64yUcXEE6AxhokWCwhmn8F2TD", "amount": "8549640.816" }, + { "type": "GENESIS", "recipient": "QQaxJuTkW5XXn4DhhRekXpdXaWcsxEfCNG", "amount": "3886200.371" }, + { "type": "GENESIS", "recipient": "QifWFqW8XWL5mcNxtdr5z1LVC7XUu9tNSK", "amount": "3116732.697" }, + { "type": "GENESIS", "recipient": "QavhBKRN4vuyzHNNqcWxjcohRAJNTdTmh4", "amount": "154670774.8" }, + { "type": "GENESIS", "recipient": "QMQyR3Hybof8WpQsXPxh19AZFCj4Z4mmke", "amount": "77724007.42" }, + { "type": "GENESIS", "recipient": "QbT3GGjp1esTXtowVk2XCtBsKoRB8mkP61", "amount": "77724007.42" }, + { "type": "GENESIS", "recipient": "QT13tVMZEtbrgJEsBBcTtnyqGveC7mtqAb", "amount": "23317202.22" }, + { "type": "GENESIS", "recipient": "QegT2Ws5YjLQzEZ9YMzWsAZMBE8cAygHZN", "amount": "12606834" }, + { "type": "GENESIS", "recipient": "QXoKRBJiJGKwvdA3jkmoUhkM7y6vuMp2pn", "amount": "65117173.41" }, + { "type": "GENESIS", "recipient": "QY6SpdBzUev9ziqkmyaxESZSbdKwqGdedn", "amount": "89382608.53" }, + { "type": "GENESIS", "recipient": "QeMxyt1nEE7tbFbioc87xhiKb4szx5DsjY", "amount": "15544801.48" }, + { "type": "GENESIS", "recipient": "QcTp3THGZvJ42f2mWsQrawGvgBoSHgHZyk", "amount": "39639243.78" }, + { "type": "GENESIS", "recipient": "QjSH91mTDN6TeV1naAcfwPhmRogufV4n1u", "amount": "23317202.22" }, + { "type": "GENESIS", "recipient": "QiFLELeLm2TFWsnknzje51wMdt3Srkjz8g", "amount": "1554480.148" }, + { "type": "GENESIS", "recipient": "QhxtJ3vvhsvVU9x2j5n2R3TXzutfLMUvBR", "amount": "23317202.22" }, + { "type": "GENESIS", "recipient": "QUtUSNQfqexZZkaZ2s9LcpqjnTezPTnuAx", "amount": "15544801.48" }, + { "type": "GENESIS", "recipient": "Qg6sPLxNMYxjEDGLLaFkkWx6ip3py5fLEt", "amount": "777240.0742" }, + { "type": "GENESIS", "recipient": "QeLixskYbdkiAHmhBVMa2Pdi85YPFqw3Ed", "amount": "38862003.71" }, + { "type": "GENESIS", "recipient": "Qary17o9qvZ2fifiVC8tF5zoBJm79n18zA", "amount": "3893972.772" }, + { "type": "GENESIS", "recipient": "QLvCWDGwzwpR29XgiThMGDX2vxyFW5rFHB", "amount": "8790585.239" }, + { "type": "GENESIS", "recipient": "Qgc77fSoAoUSVJfq62GxxTin6dBtU7Y6Hb", "amount": "194310018.5" }, + { "type": "GENESIS", "recipient": "QPmPKjwPLCuRei6abuhMtMocxAEeSuLVcv", "amount": "23317202.22" }, + { "type": "GENESIS", "recipient": "QcGfZePUN7JHs9WEEkJhXGzALy4JybiS3N", "amount": "194224522.1" }, + { "type": "GENESIS", "recipient": "QSeXGwk7eQjR8j7bndJST19qWtM2qnqL1u", "amount": "38862003.71" }, + { "type": "GENESIS", "recipient": "QU9i68h71nKTg4gwc5yJHzNRQdQEswP7Kn", "amount": "139592317.3" }, + { "type": "GENESIS", "recipient": "QdKrZGCkwXSSeXJhVA1idDXsA4VFtrjPHN", "amount": "15544801.48" }, + { "type": "GENESIS", "recipient": "QiYJ2B797xFpWYFu4XWivhGhyPXLU7S5Mr", "amount": "77724007.42" }, + { "type": "GENESIS", "recipient": "QWxqtsNXUWSjYns2wdngh4WBSWQzLoQHvx", "amount": "232613963.9" }, + { "type": "GENESIS", "recipient": "QTAGfu4FpTZ1bnvnd17YPtB3zabxfWKNeM", "amount": "101041209.6" }, + { "type": "GENESIS", "recipient": "QPtRxchgRdwdnoZRwhiAoa77AvVPNSRcQk", "amount": "114254290.9" }, + { "type": "GENESIS", "recipient": "QMcfoVc9Jat2pMFLHcuPEPnY6p6uBK6Dk7", "amount": "77724007.42" }, + { "type": "GENESIS", "recipient": "Qi84KosdwSWHZX3qz4WcMgqYGutBmj14dd", "amount": "15544801.48" }, + { "type": "GENESIS", "recipient": "QjAtcHsgig2tvdGr5tR4oGmRarhuojrAK1", "amount": "2883560.675" }, + { "type": "GENESIS", "recipient": "QPJPNLP2NMHu5athB7ydezdTA6zviCV378", "amount": "6373368.608" }, + { "type": "GENESIS", "recipient": "QfVLpmLbuUnA1JEe9FmeUAzihoBvqYDp8B", "amount": "15544801.48" }, + { "type": "GENESIS", "recipient": "QVVFdy6VLFqAFCb6XSBJLLZybiKgfgDDZV", "amount": "10725913.02" }, + { "type": "GENESIS", "recipient": "QVFXyeG1xpAR8Xg3u7oAmW8unueGAfeaKi", "amount": "31221733.78" }, + { "type": "GENESIS", "recipient": "QdtQtrM1h3TLtwAGCNyoTrW5HyiPRLhrPq", "amount": "138426457.2" }, + { "type": "GENESIS", "recipient": "QMukUMr84Mi2niz6rdhEJMkKJBve7uuRfe", "amount": "116586011.1" }, + { "type": "GENESIS", "recipient": "QZR8c7dmfwqGPujebFH1miQToJZ4JQfU1X", "amount": "217938116.8" }, + { "type": "GENESIS", "recipient": "QVV5Uu8eCxufTrBtquDKA96d7Kk8S4V7yX", "amount": "40091961.25" }, + { "type": "GENESIS", "recipient": "QY9YdgfTEUFvQ2UJszGS63qkwdENkW1PQ5", "amount": "154670774.8" }, + { "type": "GENESIS", "recipient": "QNgiswyhVyNJG4UMzvoSf29wDvGZqqs7WG", "amount": "11658601.11" }, + { "type": "GENESIS", "recipient": "QabjgFiY34oihNkUcy9hpFjQdCaypCShMe", "amount": "54406805.19" }, + { "type": "GENESIS", "recipient": "QionidPRekdshCTRL3c7idWWRAqGYcKaFN", "amount": "7772400.742" }, + { "type": "GENESIS", "recipient": "QcJdBJiVgiNBNg6ZwZAiEfYDMi5ZTQaYAa", "amount": "81386689.86" }, + { "type": "GENESIS", "recipient": "QNc8XMpPwM1HESwB7kqw8HoQ5sK2miZ2un", "amount": "190423818.2" }, + { "type": "GENESIS", "recipient": "QUP1SeaNw7CvCnmDp5ai3onWYwThS4GEpu", "amount": "3886200.371" }, + { "type": "GENESIS", "recipient": "QinToqEztNN1TsLdQEuzTHh7vUrEo6JTU2", "amount": "102440241.8" }, + { "type": "GENESIS", "recipient": "QcLJYLV4RD4GmPcoNnh7dQrWeYgiiPiqFQ", "amount": "32644083.11" }, + { "type": "GENESIS", "recipient": "QdYdYGYfgmMX4jQNWMZqLr81R3HdnuiKkv", "amount": "76169527.27" }, + { "type": "GENESIS", "recipient": "Qi62mUW5zfJhgRL8FRmCpjSCCnSKtf76S6", "amount": "76169527.27" }, + { "type": "GENESIS", "recipient": "QgFkxqQGkLW6CD95N2zTnT1PPqb9nxWp6b", "amount": "76169527.27" }, + { "type": "GENESIS", "recipient": "QfNUBudYsrrq27YqiHGLUg6BtG52W1W1ci", "amount": "15544801.48" }, + { "type": "GENESIS", "recipient": "QPSFoexnGoMH7EPdg72dM7SvqA7d4M2cu7", "amount": "37307523.56" }, + { "type": "GENESIS", "recipient": "QQxt5WMvoJ2TNScAzcoxHXPnLTeQ43nQ7N", "amount": "21995894.1" }, + { "type": "GENESIS", "recipient": "QicpACxck2oDYpzP8iWRQYD4oirCtvjok9", "amount": "93268808.9" }, + { "type": "GENESIS", "recipient": "QVTJkdQkTGgqEED9kAsp4BZbYNJqWfhgGw", "amount": "153909079.5" }, + { "type": "GENESIS", "recipient": "QQL5vCkhpXnP9F4wqNiBQsNaCocmRcDSUY", "amount": "15512934.64" }, + { "type": "GENESIS", "recipient": "QSvEex3p2LaZCVBaCyL8MpYsEpHLwed17r", "amount": "155448014.8" }, + { "type": "GENESIS", "recipient": "Qb3Xv96GucQpBG8n96QVFgcs2xXsEWW4CE", "amount": "38862003.71" }, + { "type": "GENESIS", "recipient": "QdRua9MqXufALpQFDeYiQDYk3EBGdwGXSx", "amount": "230303229.1" }, + { "type": "GENESIS", "recipient": "Qh16Umei91JqiHEVWV8AC6ED9aBqbDYuph", "amount": "231073474" }, + { "type": "GENESIS", "recipient": "QMu6HXfZCnwaNmyFjjhWTYAUW7k1x7PoVr", "amount": "231073474" }, + { "type": "GENESIS", "recipient": "QgcphUTiVHHfHg8e1LVgg5jujVES7ZDUTr", "amount": "115031531" }, + { "type": "GENESIS", "recipient": "QbQk9s4j4EAxAguBhmqA8mdtTct3qGnsrx", "amount": "138348733.2" }, + { "type": "GENESIS", "recipient": "QT79PhvBwE6vFzfZ4oh5wdKVsEazZuVJFy", "amount": "6360421.343" } ] }, "featureTriggers": { - "message": { "height": "99000" }, - "AT": { "height": "99000" }, - "assets": { "timestamp": "0" }, - "voting": { "timestamp": "1403715600000" }, - "arbitrary": { "timestamp": "1405702800000" }, - "powfix": { "timestamp": "1456426800000" }, - "v2" : { "timestamp": "1552500000000" } + "messageHeight": 99000, + "atHeight": 99000, + "assetsTimestamp": 0, + "votingTimestamp": "1403715600000", + "arbitraryTimestamp": "1405702800000", + "powfixTimestamp": "1456426800000", + "v2Timestamp": "1552500000000" } } diff --git a/src/main/java/org/qora/block/GenesisBlock.java b/src/main/java/org/qora/block/GenesisBlock.java index c3cc1af8..7b633298 100644 --- a/src/main/java/org/qora/block/GenesisBlock.java +++ b/src/main/java/org/qora/block/GenesisBlock.java @@ -3,6 +3,7 @@ package org.qora.block; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -85,7 +86,7 @@ public class GenesisBlock extends Block { info.timestamp = System.currentTimeMillis(); } - transactionsData = Arrays.asList(info.transactions); + transactionsData = new ArrayList(Arrays.asList(info.transactions)); // Add default values to transactions transactionsData.stream().forEach(transactionData -> { @@ -112,7 +113,7 @@ public class GenesisBlock extends Block { } // Convert ISSUE_ASSET transactions into initial assets - issueAssetTransactions.stream().map(transactionData -> { + initialAssets = issueAssetTransactions.stream().map(transactionData -> { IssueAssetTransactionData issueAssetTransactionData = (IssueAssetTransactionData) transactionData; return new AssetData(issueAssetTransactionData.getOwner(), issueAssetTransactionData.getAssetName(), issueAssetTransactionData.getDescription(), diff --git a/src/main/java/org/qora/data/transaction/TransactionData.java b/src/main/java/org/qora/data/transaction/TransactionData.java index 02e90f99..fdcd50e8 100644 --- a/src/main/java/org/qora/data/transaction/TransactionData.java +++ b/src/main/java/org/qora/data/transaction/TransactionData.java @@ -168,6 +168,10 @@ public abstract class TransactionData { @Override public boolean equals(Object other) { + // Comparing exact same object + if (this == other) + return true; + // If we don't have a signature then fail if (this.signature == null) return false; diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBAssetRepository.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBAssetRepository.java index 01416ad5..0a5aca53 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBAssetRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBAssetRepository.java @@ -213,7 +213,7 @@ public class HSQLDBAssetRepository implements AssetRepository { @Override public List getAggregatedOpenOrders(long haveAssetId, long wantAssetId, Integer limit, Integer offset, Boolean reverse) throws DataException { - String sql = "SELECT price, sum(amount - fulfilled), max(ordered) FROM AssetOrders " + String sql = "SELECT price, SUM(amount - fulfilled), MAX(ordered) FROM AssetOrders " + "WHERE have_asset_id = ? AND want_asset_id = ? AND is_closed = FALSE AND is_fulfilled = FALSE GROUP BY price ORDER BY price"; if (reverse != null && reverse) sql += " DESC"; diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBBlockRepository.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBBlockRepository.java index 4da188d9..b7a23ff4 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBBlockRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBBlockRepository.java @@ -3,9 +3,7 @@ package org.qora.repository.hsqldb; import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Timestamp; import java.util.ArrayList; -import java.util.Calendar; import java.util.List; import org.qora.data.block.BlockData; @@ -15,6 +13,9 @@ import org.qora.repository.BlockRepository; import org.qora.repository.DataException; import org.qora.repository.TransactionRepository; +import static org.qora.repository.hsqldb.HSQLDBRepository.toOffsetDateTime; +import static org.qora.repository.hsqldb.HSQLDBRepository.getZonedTimestampMilli; + public class HSQLDBBlockRepository implements BlockRepository { private static final String BLOCK_DB_COLUMNS = "version, reference, transaction_count, total_fees, " @@ -37,7 +38,7 @@ public class HSQLDBBlockRepository implements BlockRepository { BigDecimal totalFees = resultSet.getBigDecimal(4); byte[] transactionsSignature = resultSet.getBytes(5); int height = resultSet.getInt(6); - long timestamp = resultSet.getTimestamp(7, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + long timestamp = getZonedTimestampMilli(resultSet, 7); BigDecimal generatingBalance = resultSet.getBigDecimal(8); byte[] generatorPublicKey = resultSet.getBytes(9); byte[] generatorSignature = resultSet.getBytes(10); @@ -92,7 +93,9 @@ public class HSQLDBBlockRepository implements BlockRepository { @Override public int getHeightFromTimestamp(long timestamp) throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT MAX(height) FROM Blocks WHERE generation <= ?", new Timestamp(timestamp))) { + // Uses (generation, height) index + try (ResultSet resultSet = this.repository.checkedExecute("SELECT height FROM Blocks WHERE generation <= ? ORDER BY generation DESC LIMIT 1", + toOffsetDateTime(timestamp))) { if (resultSet == null) return 0; @@ -104,7 +107,7 @@ public class HSQLDBBlockRepository implements BlockRepository { @Override public int getBlockchainHeight() throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT MAX(height) FROM Blocks LIMIT 1")) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT height FROM Blocks ORDER BY height DESC LIMIT 1")) { if (resultSet == null) return 0; @@ -153,7 +156,7 @@ public class HSQLDBBlockRepository implements BlockRepository { saveHelper.bind("signature", blockData.getSignature()).bind("version", blockData.getVersion()).bind("reference", blockData.getReference()) .bind("transaction_count", blockData.getTransactionCount()).bind("total_fees", blockData.getTotalFees()) .bind("transactions_signature", blockData.getTransactionsSignature()).bind("height", blockData.getHeight()) - .bind("generation", new Timestamp(blockData.getTimestamp())).bind("generating_balance", blockData.getGeneratingBalance()) + .bind("generation", toOffsetDateTime(blockData.getTimestamp())).bind("generating_balance", blockData.getGeneratingBalance()) .bind("generator", blockData.getGeneratorPublicKey()).bind("generator_signature", blockData.getGeneratorSignature()) .bind("AT_count", blockData.getATCount()).bind("AT_fees", blockData.getATFees()); diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java index bcb201a6..6338d536 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java @@ -109,7 +109,7 @@ public class HSQLDBDatabaseUpdates { stmt.execute("CREATE TYPE AssetOrderID AS VARBINARY(64)"); stmt.execute("CREATE TYPE ATName AS VARCHAR(32) COLLATE SQL_TEXT_UCC_NO_PAD"); stmt.execute("CREATE TYPE ATType AS VARCHAR(32) COLLATE SQL_TEXT_UCC_NO_PAD"); - stmt.execute("CREATE TYPE ATTags AS VARCHAR(32) COLLATE SQL_TEXT_UCC_NO_PAD"); + stmt.execute("CREATE TYPE ATTags AS VARCHAR(80) COLLATE SQL_TEXT_UCC_NO_PAD"); stmt.execute("CREATE TYPE ATCode AS BLOB(64K)"); // 16bit * 1 stmt.execute("CREATE TYPE ATState AS BLOB(1M)"); // 16bit * 8 + 16bit * 4 + 16bit * 4 stmt.execute("CREATE TYPE ATCreationBytes AS BLOB(576K)"); // 16bit * 1 + 16bit * 8 @@ -133,6 +133,8 @@ public class HSQLDBDatabaseUpdates { stmt.execute("CREATE INDEX BlockGeneratorIndex ON Blocks (generator)"); // For finding blocks by reference, e.g. child blocks. stmt.execute("CREATE INDEX BlockReferenceIndex ON Blocks (reference)"); + // For finding blocks by generation timestamp or finding height of latest block immediately before generation timestamp, etc. + stmt.execute("CREATE INDEX BlockGenerationHeightIndex ON Blocks (generation, height)"); // Use a separate table space as this table will be very large. stmt.execute("SET TABLE Blocks NEW SPACE"); break; @@ -583,6 +585,11 @@ public class HSQLDBDatabaseUpdates { stmt.execute("ALTER TABLE Groups ADD COLUMN creation_group_id GroupID NOT NULL DEFAULT 0"); break; + case 37: + // Performance-improving INDEX + stmt.execute("CREATE INDEX IF NOT EXISTS BlockGenerationHeightIndex ON Blocks (generation, height)"); + break; + default: // nothing to do return false; diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBRepository.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBRepository.java index 455a53d6..c9fa6f6d 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBRepository.java @@ -7,6 +7,9 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Savepoint; import java.sql.Statement; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.util.ArrayDeque; import java.util.Deque; import java.util.TimeZone; @@ -385,4 +388,23 @@ public class HSQLDBRepository implements Repository { return e; } + /** Converts milliseconds from epoch to OffsetDateTime needed for TIMESTAMP WITH TIME ZONE columns. */ + /* package */ static OffsetDateTime toOffsetDateTime(long timestamp) { + return OffsetDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC); + } + + /** Converts OffsetDateTime from TIMESTAMP WITH TIME ZONE column to milliseconds from epoch. */ + /* package */ static long fromOffsetDateTime(OffsetDateTime offsetDateTime) { + return offsetDateTime.toInstant().toEpochMilli(); + } + + /** Returns TIMESTAMP WITH TIME ZONE column value as milliseconds from epoch, or null. */ + /* package */ static Long getZonedTimestampMilli(ResultSet resultSet, int columnIndex) throws SQLException { + OffsetDateTime offsetDateTime = resultSet.getObject(columnIndex, OffsetDateTime.class); + if (offsetDateTime == null) + return null; + + return offsetDateTime.toInstant().toEpochMilli(); + } + } \ No newline at end of file diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java index 7a128058..a13c6e3a 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java @@ -187,7 +187,12 @@ public class HSQLDBTransactionRepository implements TransactionRepository { try { // params: long timestamp, int txGroupId, byte[] reference, byte[] creatorPublicKey, BigDecimal fee, byte[] signature return (TransactionData) subclassInfos[type.value].fromBaseMethod.invoke(txRepository, timestamp, txGroupId, reference, creatorPublicKey, fee, signature); - } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { + } catch (InvocationTargetException e) { + if (e.getCause() instanceof DataException) + throw (DataException) e.getCause(); + + throw new DataException("Unsupported transaction type [" + type.name() + "] during fetch from HSQLDB repository"); + } catch (IllegalArgumentException | IllegalAccessException e) { throw new DataException("Unsupported transaction type [" + type.name() + "] during fetch from HSQLDB repository"); } } @@ -699,7 +704,12 @@ public class HSQLDBTransactionRepository implements TransactionRepository { try { subclassInfos[type.value].saveMethod.invoke(txRepository, transactionData); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + } catch (InvocationTargetException e) { + if (e.getCause() instanceof DataException) + throw (DataException) e.getCause(); + + throw new DataException("Exception during save of transaction type [" + type.name() + "] into HSQLDB repository"); + } catch (IllegalAccessException | IllegalArgumentException e) { throw new DataException("Unsupported transaction type [" + type.name() + "] during save into HSQLDB repository"); } } diff --git a/src/main/java/org/qora/transform/transaction/AtTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/AtTransactionTransformer.java index 5598c815..5cf8f5b0 100644 --- a/src/main/java/org/qora/transform/transaction/AtTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/AtTransactionTransformer.java @@ -1,12 +1,28 @@ package org.qora.transform.transaction; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigDecimal; import java.nio.ByteBuffer; +import org.qora.data.transaction.ATTransactionData; import org.qora.data.transaction.TransactionData; import org.qora.transform.TransformationException; +import org.qora.utils.Serialization; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; public class AtTransactionTransformer extends TransactionTransformer { + private static final int SENDER_LENGTH = ADDRESS_LENGTH; + private static final int RECIPIENT_LENGTH = ADDRESS_LENGTH; + private static final int AMOUNT_LENGTH = BIG_DECIMAL_LENGTH; + private static final int ASSET_ID_LENGTH = LONG_LENGTH; + private static final int DATA_SIZE_LENGTH = INT_LENGTH; + + private static final int EXTRAS_LENGTH = SENDER_LENGTH + RECIPIENT_LENGTH + AMOUNT_LENGTH + ASSET_ID_LENGTH + DATA_SIZE_LENGTH; + protected static final TransactionLayout layout = null; // Property lengths @@ -15,12 +31,48 @@ public class AtTransactionTransformer extends TransactionTransformer { } public static int getDataLength(TransactionData transactionData) throws TransformationException { - // AT Transactions aren't serialized so don't take up any space in the block. - return 0; + ATTransactionData atTransactionData = (ATTransactionData) transactionData; + + return getBaseLength(transactionData) + EXTRAS_LENGTH + atTransactionData.getMessage().length; } public static byte[] toBytes(TransactionData transactionData) throws TransformationException { - throw new TransformationException("Serialized AT Transactions should not exist!"); + try { + ATTransactionData atTransactionData = (ATTransactionData) transactionData; + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + + bytes.write(Ints.toByteArray(atTransactionData.getType().value)); + bytes.write(Longs.toByteArray(atTransactionData.getTimestamp())); + bytes.write(atTransactionData.getReference()); + + Serialization.serializeAddress(bytes, atTransactionData.getATAddress()); + + Serialization.serializeAddress(bytes, atTransactionData.getRecipient()); + + // Only emit amount if greater than zero (safer than checking assetId) + if (atTransactionData.getAmount().compareTo(BigDecimal.ZERO) > 0) { + Serialization.serializeBigDecimal(bytes, atTransactionData.getAmount()); + bytes.write(Longs.toByteArray(atTransactionData.getAssetId())); + } + + byte[] message = atTransactionData.getMessage(); + if (message.length > 0) { + bytes.write(Ints.toByteArray(message.length)); + bytes.write(message); + } else { + bytes.write(Ints.toByteArray(0)); + } + + Serialization.serializeBigDecimal(bytes, atTransactionData.getFee()); + + if (atTransactionData.getSignature() != null) + bytes.write(atTransactionData.getSignature()); + + return bytes.toByteArray(); + } catch (IOException | ClassCastException e) { + throw new TransformationException(e); + } } } diff --git a/src/main/java/org/qora/transform/transaction/TransactionTransformer.java b/src/main/java/org/qora/transform/transaction/TransactionTransformer.java index 147572af..d79d1a67 100644 --- a/src/main/java/org/qora/transform/transaction/TransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/TransactionTransformer.java @@ -210,7 +210,15 @@ public abstract class TransactionTransformer extends Transformer { return (TransactionData) method.invoke(null, byteBuffer); } catch (BufferUnderflowException e) { throw new TransformationException("Byte data too short for transaction type [" + type.value + "]"); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + } catch (InvocationTargetException e) { + if (e.getCause() instanceof BufferUnderflowException) + throw (BufferUnderflowException) e.getCause(); + + if (e.getCause() instanceof TransformationException) + throw (TransformationException) e.getCause(); + + throw new TransformationException("Internal error with transaction type [" + type.value + "] during conversion from bytes"); + } catch (IllegalAccessException | IllegalArgumentException e) { throw new TransformationException("Internal error with transaction type [" + type.value + "] during conversion from bytes"); } } @@ -231,7 +239,12 @@ public abstract class TransactionTransformer extends Transformer { try { Method method = subclassInfos[type.value].getDataLengthMethod; return (int) method.invoke(null, transactionData); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + } catch (InvocationTargetException e) { + if (e.getCause() instanceof TransformationException) + throw (TransformationException) e.getCause(); + + throw new TransformationException("Internal error with transaction type [" + type.value + "] when requesting byte length"); + } catch (IllegalAccessException | IllegalArgumentException e) { throw new TransformationException("Internal error with transaction type [" + type.value + "] when requesting byte length"); } } @@ -242,7 +255,12 @@ public abstract class TransactionTransformer extends Transformer { try { Method method = subclassInfos[type.value].toBytesMethod; return (byte[]) method.invoke(null, transactionData); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + } catch (InvocationTargetException e) { + if (e.getCause() instanceof TransformationException) + throw (TransformationException) e.getCause(); + + throw new TransformationException("Internal error with transaction type [" + type.value + "] during conversion to bytes"); + } catch (IllegalAccessException | IllegalArgumentException e) { throw new TransformationException("Internal error with transaction type [" + type.value + "] during conversion to bytes"); } } @@ -262,7 +280,12 @@ public abstract class TransactionTransformer extends Transformer { try { Method method = subclassInfos[type.value].toBytesForSigningImplMethod; return (byte[]) method.invoke(null, transactionData); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + } catch (InvocationTargetException e) { + if (e.getCause() instanceof TransformationException) + throw (TransformationException) e.getCause(); + + throw new TransformationException("Internal error with transaction type [" + type.value + "] during conversion to bytes for signing"); + } catch (IllegalAccessException | IllegalArgumentException e) { throw new TransformationException("Internal error with transaction type [" + type.value + "] during conversion to bytes for signing"); } } diff --git a/src/main/java/org/qora/transform/transaction/VoteOnPollTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/VoteOnPollTransactionTransformer.java index 367d05b4..2f0b8ed4 100644 --- a/src/main/java/org/qora/transform/transaction/VoteOnPollTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/VoteOnPollTransactionTransformer.java @@ -80,8 +80,6 @@ public class VoteOnPollTransactionTransformer extends TransactionTransformer { transformCommonBytes(transactionData, bytes); - bytes.write(voteOnPollTransactionData.getVoterPublicKey()); - Serialization.serializeSizedString(bytes, voteOnPollTransactionData.getPollName()); bytes.write(Ints.toByteArray(voteOnPollTransactionData.getOptionIndex())); diff --git a/src/main/java/org/qora/v1feeder.java b/src/main/java/org/qora/v1feeder.java index ca4f08d5..9d8f0459 100644 --- a/src/main/java/org/qora/v1feeder.java +++ b/src/main/java/org/qora/v1feeder.java @@ -15,6 +15,7 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.Security; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -23,6 +24,8 @@ import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; @@ -44,6 +47,7 @@ import org.qora.repository.Repository; import org.qora.repository.RepositoryFactory; import org.qora.repository.RepositoryManager; import org.qora.repository.hsqldb.HSQLDBRepositoryFactory; +import org.qora.settings.Settings; import org.qora.transform.TransformationException; import org.qora.transform.block.BlockTransformer; import org.qora.transform.transaction.AtTransactionTransformer; @@ -57,6 +61,11 @@ import com.google.common.primitives.Ints; public class v1feeder extends Thread { + static { + // This must go before any calls to LogManager/Logger + System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager"); + } + private static final Logger LOGGER = LogManager.getLogger(v1feeder.class); private static final int INACTIVITY_TIMEOUT = 60 * 1000; // milliseconds @@ -529,6 +538,11 @@ public class v1feeder extends Thread { String legacyATPathname = args[0]; readLegacyATs(legacyATPathname); + Security.insertProviderAt(new BouncyCastleProvider(), 0); + Security.insertProviderAt(new BouncyCastleJsseProvider(), 1); + + Settings.getInstance(); + try { RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(Controller.connectionUrl); RepositoryManager.setRepositoryFactory(repositoryFactory);