├── addressPoisonAttacks ├── addressPoisonAddresses.csv ├── addressPoisonSpends.csv ├── addressPoisonTransactions.csv ├── addressPoisonTxnSize.csv ├── addressPoisoningRaw.csv ├── findAddressPoisonDetails.php ├── findAddressPoisonTransactions.php ├── findSuccessfulAttacks.php ├── getTargetAddressDetails.php ├── targetVictimAddresses.csv └── victimAddressDetails.csv ├── address_watcher.sh ├── bsv_twitter_accounts ├── cult_of_craig.csv ├── extractBSVTwitterAccounts.php └── raw_bsv_rankings.csv ├── checkTransactions.php ├── checkTxFees.php ├── countBitcoinIRCActivity.php ├── countBlocksPerDay.php ├── countCoinJoinTransactions.php ├── countReachableBitcoinPeers.php ├── countTransactionsManyInputs.php ├── dump_mempool_hex.sh ├── extractBitcoinNodeSyncTimes.php ├── findBip39Words.php ├── findDustSpendSpam.php ├── findDustTransactionSpam.php ├── findEmptyBlocks.php ├── findMissingBitcoinProjects.php ├── findNonPatoshiDeltasAfterFastPatoshiBlocks.php ├── findOpNopSpends.php ├── findPatoshiBlockTimestampDeltas.php ├── findPatoshiMiningStreaks.php ├── findTestnetDifficultyResetBlocks.php ├── findTestnetRetargetBlocks.php ├── generateAllRepetitiveSeedPhrases.js ├── generateDifficultyHistoryCSV.php ├── getAllCoinbaseInputBlockHeights.php ├── getAllDepositsToAddress.php ├── getBitcoinPeerBandwidthStats.php ├── getBlockTimeDistribution.php ├── getFirstDepositToAddress.php ├── getHistoricalHashrateEstimates.php ├── getOFACBitcoinAddresses.php ├── goldiblocks ├── blockWeightHistory.csv ├── blockWeightvsFees.php └── goldiblocksAlgorithm.php ├── lnd-channel-backup-dropbox.sh ├── node_connection_manager ├── README.md ├── bitcoin_client.php └── node_rebalance.php ├── nonRelayedTransactions ├── addPoolSlugs.php ├── analyzeNonRelayedTransactions.php ├── findUnseenMempoolTransactions.php ├── getCoinmetricsTransactions.py └── mempoolAPIConsistencyCheck.php ├── realtimeHashrate ├── aggregateRealtimePoolStats.php ├── blendedHashrateEstimate.php ├── blendedHashrateEstimate.sh ├── calculateAverageErrorRates.php ├── calculateBlendedEstimateErrorRate.php ├── calculateRelativeErrorRates.php ├── calculateStandardDeviationErrorRates.php ├── iterate100BlockEstimateWeights.php └── outputEstimatedHashratePerBlock.php ├── regtest-network ├── networkSimulator.sh ├── send.sh └── util.sh ├── slush_pool_history ├── dumpSlushpoolHistoricalStats.php ├── estimateHistoricalPayouts.php └── slushpoolHistory.csv ├── systemMetricsDaemon.py ├── testnetBlockStormTrigger.sh └── trackUserAgentLongevity.php /addressPoisonAttacks/addressPoisonSpends.csv: -------------------------------------------------------------------------------- 1 | 797570,0.00031500 2 | 819455,0.00001358 3 | 819458,0.00002134 4 | 819569,0.00000194 5 | 819619,0.00000194 6 | 819666,0.00000194 7 | 819700,0.00000194 8 | 819724,0.00000194 9 | 819789,0.00000194 10 | 819859,0.00000194 11 | 820088,0.00000970 12 | 820124,0.00000194 13 | 820553,0.00000194 14 | 820797,0.00000194 15 | 820815,0.00000194 16 | 820862,0.00000388 17 | 821328,0.00000194 18 | 824539,0.00000194 19 | 829390,0.00000194 20 | 829605,0.00000194 21 | 829816,0.00000194 22 | 829862,0.00000194 23 | 830174,0.00000194 24 | 830180,0.00000194 25 | 830230,0.00000194 26 | 830283,0.00000194 27 | 830310,0.00000194 28 | 830462,0.00000194 29 | 830475,0.00000194 30 | 830479,0.00000194 31 | 830610,0.00000194 32 | 830673,0.00000582 33 | 831074,0.00000194 34 | 831290,0.00000194 35 | 831378,0.00000194 36 | 831497,0.00000194 37 | 831814,0.00000194 38 | 831937,0.00000194 39 | 831991,0.00000194 40 | 832104,0.00000194 41 | 832120,0.00000194 42 | 832131,0.00000194 43 | 832188,0.00000194 44 | 832191,0.00000194 45 | 832244,0.00000194 46 | 832401,0.00000194 47 | 832404,0.00000194 48 | 832473,0.00000194 49 | 832519,0.00000194 50 | 832591,0.00000388 51 | 832644,0.00000194 52 | 832687,0.00000194 53 | 832836,0.00000194 54 | 832995,0.00000194 55 | 833083,0.00000194 56 | 833119,0.00000194 57 | 833200,0.00000194 58 | 833315,0.00000194 59 | 833345,0.00000194 60 | 833382,0.00000194 61 | 833566,0.00000194 62 | 834004,0.00000194 63 | 834028,0.00000194 64 | 834073,0.00000194 65 | 834099,0.00000194 66 | 834473,0.00000194 67 | 834786,0.00000194 68 | 835613,0.00000194 69 | 836068,0.00000194 70 | 836134,0.00000194 71 | 836543,0.00000194 72 | 836587,0.00000194 73 | 836942,0.00000194 74 | 837172,0.00000194 75 | 837551,0.00000194 76 | 837680,0.00000194 77 | 837759,0.00002000 78 | 838555,0.00000194 79 | 839407,0.00000194 80 | 839668,0.00000194 81 | 842206,0.00000194 82 | 843926,0.00000194 83 | 844375,0.00000194 84 | 844475,0.00000194 85 | 844506,0.00000194 86 | 844821,0.00000194 87 | 844855,0.00000194 88 | 845180,0.00000194 89 | 845869,0.00000194 90 | 845899,0.00000194 91 | 846012,0.00000388 92 | 846141,0.00000194 93 | 847153,0.00000194 94 | 847427,0.00000194 95 | 848868,0.00000194 96 | 849791,0.00000194 97 | 850822,0.00000194 98 | 850886,0.00000194 99 | 851984,0.00000194 100 | 852202,0.00003200 101 | 853001,0.00000194 102 | 853425,0.00000194 103 | 855056,0.00000194 104 | 855159,0.00000194 105 | 855213,0.00000194 106 | 855418,0.00000194 107 | 855424,0.00000194 108 | 855486,0.00000194 109 | 855487,0.00000388 110 | 855510,0.00000194 111 | 855575,0.00000194 112 | 855877,0.00000194 113 | 856051,0.00000194 114 | 856654,0.00000194 115 | 857061,0.00000582 116 | 857145,0.00000194 117 | 857327,0.00000194 118 | 857698,0.00000194 119 | 858161,0.00000194 120 | 858976,0.00000194 121 | 860171,0.00000194 122 | 860490,0.00000194 123 | 860707,0.00000194 124 | 860789,0.00000194 125 | 861161,0.00000194 126 | 861264,0.00000194 127 | 861338,0.00000194 128 | 861850,0.00000194 129 | 861922,0.00000194 130 | 862215,0.00000194 131 | 862217,0.00000194 132 | 862248,0.00000194 133 | 862382,0.00000194 134 | 862578,0.00000194 135 | 862645,0.00000776 136 | 862957,0.00000388 137 | 863003,0.00000194 138 | 863442,0.00000194 139 | 863476,0.00000194 140 | 863691,0.00000194 141 | 863788,0.00000194 142 | 864101,0.00000194 143 | 864102,0.00000194 144 | 864152,0.00000194 145 | 864178,0.00000194 146 | 864579,0.00000194 147 | 864601,0.00000194 148 | 864931,0.00000194 149 | 864957,0.00000194 150 | 865477,0.00000194 151 | 865769,0.00000194 152 | 866095,0.00000194 153 | 866204,0.00000194 154 | 866206,0.00000194 155 | 866234,0.00000194 156 | 866247,0.00000194 157 | 866345,0.00000194 158 | 866570,0.00000194 159 | 866818,0.00000388 160 | 866875,0.00000194 161 | 866967,0.00000194 162 | 866993,0.00000194 163 | 867125,0.00000194 164 | 867261,0.00000194 165 | 867284,0.00000194 166 | 867678,0.00000194 167 | 867751,0.00000194 168 | 867757,0.00000194 169 | 867824,0.00000194 170 | 867868,0.00000194 171 | 867906,0.00000194 172 | 868007,0.00000194 173 | 868010,0.00000194 174 | 868083,0.00000194 175 | 868203,0.00000194 176 | 868274,0.00000194 177 | 868413,0.00000194 178 | 868582,0.00000194 179 | 868628,0.00000194 180 | 868840,0.00000194 181 | 868848,0.00000388 182 | 868849,0.00000194 183 | 869030,0.00000194 184 | 869047,0.00000194 185 | 869062,0.00000194 186 | 869082,0.00000194 187 | 869091,0.00000194 188 | 869096,0.00000194 189 | 869098,0.00000194 190 | 869236,0.00000388 191 | 869264,0.00000194 192 | 869339,0.00000194 193 | 869500,0.00000194 194 | 869664,0.00000194 195 | 869711,0.00001358 196 | 869741,0.00000194 197 | 869810,0.00000194 198 | 869816,0.00000194 199 | 869929,0.00000194 200 | 869931,0.00000194 201 | 870056,0.00000194 202 | 870070,0.00000194 203 | 870071,0.00000746 204 | 870072,0.00002643 205 | 870079,0.00001017 206 | 870081,0.00000113 207 | 870084,0.00000113 208 | 870087,0.00000970 209 | 870094,0.00000970 210 | 870113,0.00000113 211 | 870115,0.00000194 212 | 870116,0.00000194 213 | 870137,0.00000251 214 | 870142,0.00000194 215 | 870152,0.00000194 216 | 870156,0.00000113 217 | 870159,0.00000194 218 | 870169,0.00000194 219 | 870173,0.00000113 220 | 870188,0.00000138 221 | 870193,0.00000113 222 | 870194,0.00000113 223 | 870204,0.00000113 224 | 870214,0.00000138 225 | 870215,0.00000194 226 | 870223,0.00000194 227 | 870237,0.00000194 228 | 870245,0.00000194 229 | 870251,0.00000194 230 | 870255,0.00000194 231 | 870261,0.00000194 232 | 870265,0.00000194 233 | 870266,0.00000194 234 | 870273,0.00000194 235 | 870317,0.00000113 236 | 870319,0.00000194 237 | 870321,0.00000113 238 | 870324,0.00000226 239 | 870336,0.00000194 240 | 870343,0.00000388 241 | 870356,0.00000138 242 | 870379,0.00000869 243 | 870385,0.00000138 244 | 870386,0.00000194 245 | 870394,0.00000138 246 | 870402,0.00000194 247 | 870403,0.00000194 248 | 870459,0.00000194 249 | 870475,0.00000113 250 | 870477,0.00000194 251 | 870482,0.00000194 252 | 870513,0.00000113 253 | 870514,0.00000194 254 | 870532,0.00000113 255 | 870533,0.00000194 256 | 870534,0.00002430 257 | 870541,0.00000194 258 | 870553,0.00000194 259 | 870562,0.00000194 260 | 870563,0.00000194 261 | 870564,0.00000194 262 | 870567,0.00000194 263 | 870575,0.00000113 264 | 870576,0.00000194 265 | 870613,0.00000138 266 | 870626,0.00000194 267 | 870663,0.00000113 268 | 870710,0.00000113 269 | 870714,0.00000194 270 | 870746,0.00000194 271 | 870750,0.00000194 272 | 870753,0.00000388 273 | 870754,0.00000194 274 | 870774,0.00000113 275 | 870777,0.00000194 276 | 870796,0.00000194 277 | 870802,0.00000138 278 | 870809,0.00000113 279 | 870826,0.00000194 280 | 870845,0.00000113 281 | 870850,0.00000113 282 | 870872,0.00000113 283 | 870880,0.00000194 284 | 870885,0.00000194 285 | 870889,0.00000194 286 | 870890,0.00000113 287 | 870917,0.00000113 288 | 870962,0.00000138 289 | 870974,0.00000113 290 | 870987,0.00000194 291 | 871013,0.00000388 292 | 871032,0.00000138 293 | 871065,0.00000113 294 | 871075,0.00000113 295 | 871090,0.00000138 296 | 871110,0.00000194 297 | 871183,0.00000194 298 | 871188,0.00000194 299 | 871195,0.00000194 300 | 871207,0.00000194 301 | 871225,0.00000113 302 | 871239,0.00000194 303 | 871242,0.00000138 304 | 871276,0.00000138 305 | 871282,0.00000113 306 | 871284,0.00000113 307 | 871293,0.00000138 308 | 871295,0.00000194 309 | 871302,0.00000138 310 | 871319,0.00000194 311 | 871323,0.00000138 312 | 871340,0.00000226 313 | 871342,0.00000113 314 | 871344,0.00000113 315 | 871345,0.00000138 316 | 871351,0.00000138 317 | 871352,0.00000138 318 | 871365,0.00000113 319 | 871384,0.00000113 320 | 871393,0.00000138 321 | 871396,0.00000113 322 | 871427,0.00000194 323 | 871437,0.00000113 324 | 871438,0.00000113 325 | 871439,0.00000113 326 | 871440,0.00000113 327 | 871447,0.00000385 328 | 871449,0.00000113 329 | 871453,0.00000194 330 | 871470,0.00000194 331 | 871478,0.00000138 332 | 871486,0.00000138 333 | 871497,0.00000113 334 | 871531,0.00000113 335 | 871539,0.00000113 336 | 871555,0.00000138 337 | 871584,0.00000194 338 | 871646,0.00000138 339 | 871729,0.00000341 340 | 871743,0.00000138 341 | 871754,0.00000194 342 | 871757,0.00000138 343 | 871791,0.00000113 344 | 871792,0.00000113 345 | 871797,0.00000113 346 | 871799,0.00000194 347 | 871801,0.00000226 348 | 871829,0.00000194 349 | 871830,0.00000194 350 | 871839,0.00000194 351 | 871870,0.00000339 352 | 871882,0.00000138 353 | 871930,0.00000194 354 | 871944,0.00000194 355 | 871966,0.00000194 356 | 871976,0.00000113 357 | 871982,0.00000138 358 | 872009,0.00003104 359 | 872013,0.00000226 360 | 872029,0.00000194 361 | 872039,0.00000194 362 | 872045,0.00000113 363 | 872070,0.00000251 364 | 872078,0.00000194 365 | 872104,0.00000194 366 | 872162,0.00000194 367 | 872167,0.00000138 368 | 872176,0.00000113 369 | 872191,0.00000194 370 | 872195,0.00000113 371 | 872228,0.00000138 372 | 872230,0.00000113 373 | 872238,0.00000194 374 | 872243,0.00000113 375 | 872245,0.00000194 376 | 872268,0.00000276 377 | 872344,0.00000113 378 | 872357,0.00000194 379 | 872359,0.00000113 380 | 872374,0.00000113 381 | 872392,0.00000194 382 | 872431,0.00000307 383 | 872437,0.00000194 384 | 872450,0.00000194 385 | 872496,0.00000113 386 | 872504,0.00000113 387 | 872506,0.00000276 388 | 872546,0.00000307 389 | 872579,0.00000194 390 | 872590,0.00000138 391 | 872622,0.00000113 392 | 872659,0.00000113 393 | 872697,0.00000113 394 | 872703,0.00000113 395 | 872727,0.00000388 396 | 872751,0.00000138 397 | 872755,0.00000138 398 | 872797,0.00000113 399 | 872851,0.00000194 400 | 872878,0.00000113 401 | 872958,0.00000113 402 | 872976,0.00000113 403 | 872998,0.00000138 404 | 873000,0.00000138 405 | 873019,0.00000194 406 | 873073,0.00000138 407 | 873118,0.00000388 408 | 873128,0.00000113 409 | 873154,0.00000138 410 | 873157,0.00000113 411 | 873160,0.00000113 412 | 873204,0.00000194 413 | 873270,0.00000194 414 | 873307,0.00000113 415 | 873340,0.00000194 416 | 873343,0.00000113 417 | 873350,0.00000452 418 | 873361,0.00000194 419 | 873369,0.00000138 420 | 873374,0.00000113 421 | 873378,0.00000113 422 | 873382,0.00000194 423 | 873383,0.00000113 424 | 873387,0.00000113 425 | 873390,0.00000194 426 | 873401,0.00000194 427 | 873414,0.00000113 428 | 873454,0.00000194 429 | 873462,0.00000138 430 | 873478,0.00000138 431 | 873501,0.00000113 432 | 873505,0.00000113 433 | 873521,0.00000138 434 | 873574,0.00000307 435 | 873581,0.00000113 436 | 873634,0.00000138 437 | 873649,0.00000194 438 | 873681,0.00000388 439 | 873806,0.00000251 440 | 873842,0.00000138 441 | 873894,0.00000194 442 | 873945,0.00000138 443 | 873956,0.00000138 444 | 873973,0.00000113 445 | 873974,0.00000138 446 | 873985,0.00000113 447 | 874026,0.00000138 448 | 874063,0.00000138 449 | 874077,0.00000113 450 | 874094,0.00000194 451 | 874124,0.00000138 452 | 874127,0.00000113 453 | 874159,0.00000339 454 | 874167,0.00000194 455 | 874232,0.00000113 456 | 874253,0.00000194 457 | 874270,0.00000113 458 | 874274,0.00000138 459 | 874275,0.00000138 460 | 874360,0.00000194 461 | 874395,0.00000113 462 | 874460,0.00000388 463 | 874528,0.00000276 464 | 874541,0.00000113 465 | 874565,0.00000138 466 | 874635,0.00000138 467 | 874656,0.00000113 468 | 874659,0.00000194 469 | 874763,0.00000138 470 | 874782,0.00000113 471 | 874796,0.00000194 472 | 874824,0.00000113 473 | 874866,0.00000113 474 | 874879,0.00000194 475 | 874911,0.00000113 476 | 874956,0.00000194 477 | 874981,0.00000828 478 | 875010,0.00000138 479 | 875045,0.00000113 480 | 875073,0.00000138 481 | 875103,0.00000138 482 | 875146,0.00000138 483 | 875149,0.00000194 484 | 875214,0.00000138 485 | 875301,0.00000138 486 | 875342,0.00000138 487 | 875345,0.00000138 488 | 875351,0.00000138 489 | 875363,0.00000194 490 | 875391,0.00000113 491 | 875463,0.00000113 492 | 875483,0.00000113 493 | 875488,0.00000138 494 | 875496,0.00000113 495 | 875500,0.00000276 496 | 875502,0.00000113 497 | 875564,0.00000113 498 | 875565,0.00000138 499 | 875574,0.00000194 500 | 875580,0.00000194 501 | 875584,0.00000113 502 | 875607,0.00000138 503 | 875651,0.00000194 504 | 875709,0.00000138 505 | 875713,0.00000138 506 | 875786,0.00000113 507 | 875826,0.00000113 508 | 875960,0.00000138 509 | 876026,0.00000138 510 | 876047,0.00000113 511 | 876053,0.00000194 512 | 876092,0.00000113 513 | 876113,0.00000276 514 | 876123,0.00000138 515 | 876135,0.00000194 516 | 876149,0.00000251 517 | 876168,0.00000138 518 | 876176,0.00000113 519 | 876187,0.00000194 520 | 876198,0.00000113 521 | 876223,0.00000113 522 | 876257,0.00000113 523 | 876301,0.00000388 524 | 876307,0.00000138 525 | 876343,0.00000138 526 | 876376,0.00000138 527 | 876397,0.00000138 528 | 876428,0.00000194 529 | 876440,0.00000113 530 | 876476,0.00000276 531 | 876558,0.00000194 532 | 876606,0.00000113 533 | 876632,0.00000113 534 | 876655,0.00000276 535 | 876740,0.00000138 536 | 876745,0.00000194 537 | 876782,0.00000388 538 | 876787,0.00000113 539 | 876794,0.00000113 540 | 876810,0.00000194 541 | 876868,0.00000113 542 | 876869,0.00000113 543 | 876887,0.00000113 544 | 876903,0.00000113 545 | 876920,0.00000194 546 | 876924,0.00000138 547 | 876938,0.00000113 548 | 876940,0.00000138 549 | 876941,0.00000113 550 | 876968,0.00000138 551 | 876979,0.00000138 552 | 876988,0.00000113 553 | 876991,0.00000113 554 | 877028,0.00000113 555 | 877030,0.00000113 556 | 877049,0.00000113 557 | 877066,0.00000113 558 | 877071,0.00000194 559 | 877074,0.00000445 560 | 877075,0.00000113 561 | 877077,0.00000138 562 | 877104,0.00000113 563 | 877108,0.00000138 564 | 877146,0.00000113 565 | 877159,0.00000194 566 | 877167,0.00000113 567 | 877170,0.00000113 568 | 877200,0.00000138 569 | 877210,0.00000194 570 | 877213,0.00000414 571 | 877214,0.00000138 572 | 877221,0.00000138 573 | 877223,0.00000138 574 | 877233,0.00000226 575 | 877236,0.00000138 576 | 877240,0.00000138 577 | 877246,0.00000388 578 | 877253,0.00000138 579 | 877266,0.00000138 580 | 877269,0.00000113 581 | 877272,0.00000138 582 | 877354,0.00000194 583 | 877365,0.00000226 584 | 877368,0.00000194 585 | 877387,0.00000113 586 | 877393,0.00000113 587 | 877426,0.00000276 588 | 877435,0.00000113 589 | 877468,0.00000138 590 | 877480,0.00000138 591 | 877542,0.00000138 592 | 877547,0.00000194 593 | 877548,0.00000138 594 | 877554,0.00000138 595 | 877561,0.00000113 596 | 877589,0.00000113 597 | 877648,0.00000194 598 | 877650,0.00000113 599 | 877663,0.00000138 600 | 877671,0.00000113 601 | 877673,0.00000113 602 | 877724,0.00000276 603 | 877767,0.00000113 604 | 877816,0.00000113 605 | 877817,0.00000113 606 | 877833,0.00000113 607 | 877884,0.00000194 608 | 877908,0.00000194 609 | 877914,0.00000194 610 | 877918,0.00000138 611 | 877929,0.00000113 612 | 877948,0.00000113 613 | 877960,0.00000113 614 | 877963,0.00000307 615 | 877988,0.00000113 616 | 877992,0.00000113 617 | 878000,0.00000113 618 | 878023,0.00000113 619 | 878024,0.00000138 620 | 878036,0.00000113 621 | 878041,0.00000113 622 | 878069,0.00000194 623 | 878089,0.00000113 624 | 878097,0.00000138 625 | 878106,0.00000138 626 | 878129,0.00000113 627 | 878143,0.00000113 628 | 878186,0.00000138 629 | 878188,0.00000194 630 | 878232,0.00000388 631 | 878235,0.00000138 632 | 878238,0.00000138 633 | 878259,0.00000113 634 | 878280,0.00000113 635 | 878298,0.00000113 636 | 878313,0.00000113 637 | 878334,0.00000113 638 | 878337,0.00000113 639 | 878338,0.00000113 640 | 878341,0.00000194 641 | 878346,0.00000138 642 | 878376,0.00000113 643 | 878384,0.00000113 644 | 878390,0.00000113 645 | 878406,0.00000113 646 | 878462,0.00000113 647 | 878474,0.00000138 648 | 878489,0.00000138 649 | 878492,0.00000194 650 | 878505,0.00000194 651 | 878512,0.00000113 652 | 878514,0.00000113 653 | 878517,0.00000194 654 | 878521,0.00000138 655 | 878533,0.00000194 656 | 878546,0.00000138 657 | 878552,0.00000113 658 | 878583,0.00000138 659 | 878592,0.00000138 660 | 878603,0.00000138 661 | 878616,0.00000113 662 | 878624,0.00000194 663 | 878629,0.00000113 664 | 878631,0.00000113 665 | 878640,0.00000113 666 | 878676,0.00000113 667 | 878698,0.00000138 668 | 878710,0.00000226 669 | 878780,0.00000194 670 | 878786,0.00000113 671 | 878847,0.00000113 672 | 878850,0.00000113 673 | 878894,0.00000194 674 | 878924,0.00000113 675 | 878926,0.00000138 676 | 878929,0.00000113 677 | 878933,0.00000477 678 | 878946,0.00000113 679 | 878951,0.00000113 680 | 878952,0.00000113 681 | 878970,0.00000414 682 | 878971,0.00000966 683 | 878972,0.00001794 684 | 878973,0.00001493 685 | 878975,0.00000113 686 | 878976,0.00001017 687 | 878977,0.00002486 688 | 878978,0.00001130 689 | 878979,0.00002486 690 | 878980,0.00002599 691 | 878991,0.00000113 692 | 879006,0.00011178 693 | 879007,0.00327198 694 | 879008,0.00702696 695 | 879011,0.00032706 696 | 879015,0.00062238 697 | 879016,0.00728671 698 | 879020,0.00030100 699 | 879040,0.00000194 700 | 879076,0.00000113 701 | 879095,0.00000113 702 | 879110,0.00000113 703 | 879141,0.00006929 704 | 879142,0.00040663 705 | 879145,0.00025086 706 | 879146,0.00002147 707 | 879151,0.00004407 708 | 879152,0.00004934 709 | 879153,0.00002373 710 | 879156,0.00014916 711 | 879157,0.00024182 712 | 879158,0.00005311 713 | 879160,0.00036386 714 | 879161,0.00017628 715 | 879162,0.00009944 716 | 879163,0.00046669 717 | 879165,0.00030849 718 | 879168,0.00009379 719 | 879177,0.00000113 720 | 879179,0.00001469 721 | 879180,0.00000565 722 | 879183,0.00003277 723 | 879186,0.00002147 724 | 879189,0.00011978 725 | 879190,0.00005085 726 | 879191,0.00001469 727 | 879192,0.00000791 728 | 879193,0.00000226 729 | 879194,0.00002373 730 | 879196,0.00000194 731 | 879197,0.00000452 732 | 879198,0.00010986 733 | 879200,0.00000388 734 | 879203,0.00000904 735 | 879204,0.00028815 736 | 879208,0.00007232 737 | 879209,0.00005110 738 | 879210,0.00018532 739 | 879213,0.00045878 740 | 879215,0.00041358 741 | 879238,0.00030284 742 | 879239,0.00000113 743 | 879242,0.00011526 744 | 879243,0.00002373 745 | 879251,0.00026668 746 | 879254,0.00000113 747 | 879264,0.00005813 748 | 879266,0.00010747 749 | 879267,0.00049155 750 | 879268,0.00049381 751 | 879269,0.00057065 752 | 879279,0.00020679 753 | 879280,0.00013560 754 | 879281,0.00003164 755 | 879282,0.00018984 756 | 879283,0.00025199 757 | 879284,0.00027798 758 | 879287,0.00021809 759 | 879288,0.00023391 760 | 879290,0.00004068 761 | 879293,0.00006102 762 | 879294,0.00005537 763 | 879295,0.00008701 764 | 879297,0.00014125 765 | 879298,0.00052884 766 | 879299,0.00020905 767 | 879302,0.00038081 768 | 879303,0.00022939 769 | 879310,0.00000113 770 | 879311,0.00000452 771 | 879312,0.00015368 772 | 879315,0.00002260 773 | 879325,0.00014125 774 | 879326,0.00001243 775 | 879327,0.00003842 776 | 879328,0.00016159 777 | 879331,0.00000113 778 | 879333,0.00019210 779 | 879334,0.00019662 780 | 879402,0.00000113 781 | 879430,0.00000113 782 | 879434,0.00000113 783 | 879443,0.00000113 784 | 879451,0.00000194 785 | 879454,0.00000113 786 | 879509,0.00000194 787 | 879515,0.00000194 788 | 879538,0.00000113 789 | 879577,0.00000113 790 | 879578,0.00000113 791 | 879608,0.00006102 792 | 879614,0.00009831 793 | 879615,0.00014690 794 | 879616,0.00000113 795 | 879643,0.00000113 796 | 879655,0.00000307 797 | 879677,0.00000194 798 | 879695,0.00000113 799 | 879702,0.00016385 800 | 879703,0.00002599 801 | 879704,0.00009831 802 | 879705,0.00021583 803 | 879707,0.00018984 804 | 879717,0.00002486 805 | 879718,0.00018758 806 | 879719,0.00008362 807 | 879723,0.00009718 808 | 879725,0.00006554 809 | 879726,0.00008588 810 | 879728,0.00009040 811 | 879730,0.00016724 812 | 879731,0.00006215 813 | 879732,0.00000904 814 | 879733,0.00030397 815 | 879734,0.00000339 816 | 879735,0.00029832 817 | 879736,0.00004633 818 | 879737,0.00024182 819 | 879738,0.00018758 820 | 879739,0.00000452 821 | 879740,0.00006780 822 | 879743,0.00006215 823 | 879744,0.00028476 824 | 879752,0.00024295 825 | 879753,0.00006328 826 | 879754,0.00009831 827 | 879775,0.00000113 828 | 879776,0.00000565 829 | 879777,0.00014916 830 | 879778,0.00002793 831 | 879783,0.00012995 832 | 879784,0.00008136 833 | 879806,0.00000113 834 | 879808,0.00000194 835 | 879828,0.00011752 836 | 879829,0.00009686 837 | 879831,0.00018532 838 | 879832,0.00013447 839 | 879835,0.00020276 840 | 879843,0.00001017 841 | 879844,0.00014125 842 | 879845,0.00001469 843 | 879846,0.00017063 844 | 879848,0.00017741 845 | 879849,0.00005424 846 | 879850,0.00001469 847 | 879851,0.00008362 848 | 879852,0.00013786 849 | 879853,0.00026668 850 | 879854,0.00014464 851 | 879856,0.00014464 852 | 879857,0.00030171 853 | 879858,0.00008136 854 | 879859,0.00012995 855 | 879860,0.00000113 856 | 879861,0.00002712 857 | 879862,0.00008814 858 | 879863,0.00002825 859 | 879864,0.00000339 860 | 879867,0.00008927 861 | 879868,0.00004633 862 | 879869,0.00005989 863 | 879870,0.00030849 864 | 879871,0.00016385 865 | 879872,0.00013673 866 | 879873,0.00029606 867 | 879874,0.00002034 868 | 879875,0.00004068 869 | 879876,0.00019549 870 | 879877,0.00007006 871 | 879878,0.00014690 872 | 879879,0.00018758 873 | 879880,0.00009492 874 | 879884,0.00000565 875 | 879885,0.00001243 876 | 879887,0.00002373 877 | 879894,0.00000194 878 | 879899,0.00000113 879 | 879901,0.00022939 880 | 879943,0.00000194 881 | 879949,0.00015933 882 | 879956,0.00004520 883 | 879965,0.00002486 884 | 879978,0.00004520 885 | 879982,0.00000113 886 | 879983,0.00010735 887 | 879984,0.00013447 888 | 879986,0.00003164 889 | 879987,0.00000565 890 | 879988,0.00013221 891 | 879989,0.00010703 892 | 879990,0.00017063 893 | 879991,0.00001695 894 | 879998,0.00000113 895 | 880047,0.00000194 896 | 880129,0.00000194 897 | 880163,0.00000194 898 | 880213,0.00000194 899 | 880223,0.00000194 900 | 880265,0.00000194 901 | 880356,0.00000194 902 | 880446,0.00000194 903 | 880488,0.00000194 904 | 880516,0.00000194 905 | 880521,0.00000388 906 | 880629,0.00000194 907 | 880783,0.00000194 908 | 880893,0.00004850 909 | 880906,0.00000194 910 | 880933,0.00000388 911 | 880982,0.00000194 912 | 881003,0.00003104 913 | 881004,0.00005626 914 | 881006,0.00008730 915 | 881007,0.00052186 916 | 881009,0.00000582 917 | 881011,0.00024250 918 | 881012,0.00021340 919 | 881015,0.00011446 920 | 881016,0.00020564 921 | 881021,0.00011640 922 | 881027,0.00012222 923 | 881046,0.00000194 924 | 881050,0.00000970 925 | 881051,0.00017460 926 | 881060,0.00012028 927 | 881061,0.00041322 928 | 881063,0.00041128 929 | 881082,0.00000194 930 | 881088,0.00008924 931 | 881089,0.00051410 932 | 881090,0.00000388 933 | 881124,0.00018430 934 | 881126,0.00008730 935 | 881127,0.00017460 936 | 881130,0.00023086 937 | 881134,0.00028906 938 | 881136,0.00063826 939 | 881138,0.00046172 940 | 881139,0.00007566 941 | 881140,0.00002716 942 | 881141,0.00010476 943 | 881144,0.00000582 944 | 881145,0.00008536 945 | 881150,0.00004656 946 | 881151,0.00001940 947 | 881155,0.00003104 948 | 881156,0.00039382 949 | 881158,0.00023280 950 | 881159,0.00090986 951 | 881160,0.00026190 952 | 881161,0.00020176 953 | 881162,0.00016878 954 | 881163,0.00016878 955 | 881164,0.00052380 956 | 881167,0.00058782 957 | 881168,0.00363556 958 | 881169,0.00770374 959 | 881170,0.00536798 960 | 881172,0.00000194 961 | 797570,0.00021 962 | 819455,0.000042 963 | 819458,0.000066 964 | 819569,0.000006 965 | 819619,0.000006 966 | 819666,0.000006 967 | 819700,0.000006 968 | 819724,0.000006 969 | 819789,0.000006 970 | 819859,0.000006 971 | 820088,0.000030 972 | 820124,0.000006 973 | 820553,0.000006 974 | 820797,0.000006 975 | 820815,0.000006 976 | 820862,0.000120 977 | 821328,0.000006 978 | 824539,0.000006 979 | 829390,0.000006 980 | 829605,0.000006 981 | 829816,0.000006 982 | 829862,0.000006 983 | 830174,0.000006 984 | 830180,0.000006 985 | 830230,0.000006 986 | 830283,0.000006 987 | 830310,0.000006 988 | 830462,0.000006 989 | 830475,0.000006 990 | 830479,0.000006 991 | 830610,0.000006 992 | 830673,0.000018 993 | 831074,0.000006 994 | 831290,0.000006 995 | 831378,0.000006 996 | 831497,0.000006 997 | 831814,0.000006 998 | 831937,0.000006 999 | 831991,0.000006 1000 | 832104,0.000006 1001 | 832120,0.000006 1002 | 832131,0.000006 1003 | 832188,0.000006 1004 | 832191,0.000006 1005 | 832244,0.000006 1006 | 832401,0.000006 1007 | 832404,0.000006 1008 | 832473,0.000006 1009 | 832519,0.000006 1010 | 832591,0.000012 1011 | 832644,0.000006 1012 | 832687,0.000006 1013 | 832836,0.000006 1014 | 832995,0.000006 1015 | 833083,0.000006 1016 | 833119,0.000006 1017 | 833200,0.000006 1018 | 833315,0.000006 1019 | 833345,0.000006 1020 | 833382,0.000006 1021 | 833566,0.000006 1022 | 834004,0.000006 1023 | 834028,0.000006 1024 | 834073,0.000006 1025 | 834099,0.000006 1026 | 834473,0.000006 1027 | 834786,0.000006 1028 | 835613,0.000006 1029 | 836068,0.000006 1030 | 836134,0.000006 1031 | 836543,0.000006 1032 | 836587,0.000006 1033 | 836942,0.000006 1034 | 837172,0.000006 1035 | 837551,0.000006 1036 | 837680,0.000006 1037 | 837759,0.000012 1038 | 838555,0.000006 1039 | 839407,0.000006 1040 | 839668,0.000006 1041 | 842206,0.000006 1042 | 843926,0.000006 1043 | 844375,0.000006 1044 | 844475,0.000006 1045 | 844506,0.000006 1046 | 844821,0.000006 1047 | 844855,0.000006 1048 | 845180,0.000006 1049 | 845869,0.000006 1050 | 845899,0.000006 1051 | 846012,0.000012 1052 | 846141,0.000006 1053 | 847153,0.000006 1054 | 847427,0.000006 1055 | 848868,0.000006 1056 | 849791,0.000006 1057 | 850822,0.000006 1058 | 850886,0.000006 1059 | 851984,0.000006 1060 | 852202,0.000024 1061 | 853001,0.000006 1062 | 853425,0.000006 1063 | 855056,0.000006 1064 | 855159,0.000006 1065 | 855213,0.000006 1066 | 855418,0.000006 1067 | 855424,0.000006 1068 | 855486,0.000006 1069 | 855487,0.000012 1070 | 855510,0.000006 1071 | 855575,0.000006 1072 | 855877,0.000006 1073 | 856051,0.000006 1074 | 856654,0.000006 1075 | 857061,0.000018 1076 | 857145,0.000006 1077 | 857327,0.000006 1078 | 857698,0.000006 1079 | 858161,0.000006 1080 | 858976,0.000006 1081 | 860171,0.000006 1082 | 860490,0.000006 1083 | 860707,0.000006 1084 | 860789,0.000006 1085 | 861161,0.000006 1086 | 861264,0.000006 1087 | 861338,0.000006 1088 | 861850,0.000006 1089 | 861922,0.000006 1090 | 862215,0.000006 1091 | 862217,0.000006 1092 | 862248,0.000006 1093 | 862382,0.000006 1094 | 862578,0.000006 1095 | 862645,0.000024 1096 | 862957,0.000012 1097 | 863003,0.000006 1098 | 863442,0.000006 1099 | 863476,0.000006 1100 | 863691,0.000006 1101 | 863788,0.000006 1102 | 864101,0.000006 1103 | 864102,0.000006 1104 | 864152,0.000006 1105 | 864178,0.000006 1106 | 864579,0.000006 1107 | 864601,0.000006 1108 | 864931,0.000006 1109 | 864957,0.000006 1110 | 865477,0.000006 1111 | 865769,0.000006 1112 | 866095,0.000006 1113 | 866204,0.000006 1114 | 866206,0.000006 1115 | 866234,0.000006 1116 | 866247,0.000006 1117 | 866345,0.000006 1118 | 866570,0.000006 1119 | 866818,0.000012 1120 | 866875,0.000006 1121 | 866967,0.000006 1122 | 866993,0.000006 1123 | 867125,0.000006 1124 | 867261,0.000006 1125 | 867284,0.000006 1126 | 867678,0.000006 1127 | 867751,0.000006 1128 | 867757,0.000006 1129 | 867824,0.000006 1130 | 867868,0.000006 1131 | 867906,0.000006 1132 | 868007,0.000006 1133 | 868010,0.000006 1134 | 868083,0.000006 1135 | 868203,0.000006 1136 | 868274,0.000006 1137 | 868413,0.000006 1138 | 868582,0.000006 1139 | 868628,0.000006 1140 | 868840,0.000006 1141 | 868848,0.000012 1142 | 868849,0.000006 1143 | 869030,0.000006 1144 | 869047,0.000006 1145 | 869062,0.000006 1146 | 869082,0.000006 1147 | 869091,0.000006 1148 | 869096,0.000006 1149 | 869098,0.000006 1150 | 869236,0.000012 1151 | 869264,0.000006 1152 | 869339,0.000006 1153 | 869500,0.000006 1154 | 869664,0.000006 1155 | 869711,0.000042 1156 | 869741,0.000006 1157 | 869810,0.000006 1158 | 869816,0.000006 1159 | 869929,0.000006 1160 | 869931,0.000006 1161 | 870056,0.000006 1162 | 870070,0.000006 1163 | 870071,0.0000066 1164 | 870072,0.0000066 1165 | 870079,0.0000033 1166 | 870081,0.0000033 1167 | 870084,0.0000033 1168 | 870087,0.000006 1169 | 870094,0.00003 1170 | 870113,0.0000033 1171 | 870115,0.000006 1172 | 870116,0.000006 1173 | 870137,0.0000093 1174 | 870142,0.000006 1175 | 870152,0.000006 1176 | 870156,0.0000033 1177 | 870159,0.000006 1178 | 870169,0.000006 1179 | 870173,0.0000033 1180 | 870188,0.000006 1181 | 870193,0.0000033 1182 | 870194,0.0000033 1183 | 870204,0.0000033 1184 | 870214,0.000006 1185 | 870215,0.000006 1186 | 870223,0.000006 1187 | 870237,0.000006 1188 | 870245,0.000006 1189 | 870251,0.000006 1190 | 870255,0.000006 1191 | 870261,0.000006 1192 | 870265,0.000006 1193 | 870266,0.000006 1194 | 870273,0.000006 1195 | 870317,0.0000033 1196 | 870319,0.000006 1197 | 870321,0.0000033 1198 | 870324,0.0000066 1199 | 870336,0.000006 1200 | 870343,0.000012 1201 | 870356,0.000006 1202 | 870379,0.0000099 1203 | 870385,0.000006 1204 | 870386,0.000006 1205 | 870394,0.000006 1206 | 870402,0.000006 1207 | 870403,0.000006 1208 | 870459,0.000006 1209 | 870475,0.0000033 1210 | 870477,0.000006 1211 | 870482,0.000006 1212 | 870513,0.0000033 1213 | 870514,0.000006 1214 | 870532,0.0000033 1215 | 870533,0.000006 1216 | 870534,0.0000297 1217 | 870541,0.000006 1218 | 870553,0.000006 1219 | 870562,0.000006 1220 | 870563,0.000006 1221 | 870564,0.000006 1222 | 870567,0.000006 1223 | 870575,0.0000033 1224 | 870576,0.000006 1225 | 870613,0.000006 1226 | 870626,0.000006 1227 | 870663,0.0000033 1228 | 870710,0.0000033 1229 | 870714,0.000006 1230 | 870746,0.000006 1231 | 870750,0.000006 1232 | 870753,0.000012 1233 | 870754,0.000006 1234 | 870774,0.0000033 1235 | 870777,0.000006 1236 | 870796,0.000006 1237 | 870802,0.000006 1238 | 870809,0.0000033 1239 | 870826,0.000006 1240 | 870845,0.0000033 1241 | 870850,0.0000033 1242 | 870872,0.0000033 1243 | 870880,0.000006 1244 | 870885,0.000006 1245 | 870889,0.000006 1246 | 870890,0.0000033 1247 | 870917,0.0000033 1248 | 870962,0.000006 1249 | 870974,0.0000033 1250 | 870987,0.000006 1251 | 871013,0.000012 1252 | 871032,0.000006 1253 | 871065,0.0000033 1254 | 871075,0.0000033 1255 | 871090,0.000006 1256 | 871110,0.000006 1257 | 871183,0.000006 1258 | 871188,0.000006 1259 | 871195,0.000006 1260 | 871207,0.000006 1261 | 871225,0.0000033 1262 | 871239,0.000006 1263 | 871242,0.000006 1264 | 871276,0.000006 1265 | 871282,0.0000033 1266 | 871284,0.0000033 1267 | 871293,0.000006 1268 | 871295,0.000006 1269 | 871302,0.000006 1270 | 871319,0.000006 1271 | 871323,0.000006 1272 | 871340,0.0000066 1273 | 871342,0.0000033 1274 | 871344,0.0000033 1275 | 871345,0.000006 1276 | 871351,0.000006 1277 | 871352,0.000006 1278 | 871365,0.0000033 1279 | 871384,0.0000033 1280 | 871393,0.000006 1281 | 871396,0.0000033 1282 | 871427,0.000006 1283 | 871437,0.0000033 1284 | 871438,0.0000033 1285 | 871439,0.0000033 1286 | 871440,0.0000033 1287 | 871447,0.00000623 1288 | 871449,0.0000033 1289 | 871453,0.000006 1290 | 871470,0.000006 1291 | 871478,0.000006 1292 | 871486,0.000006 1293 | 871497,0.0000033 1294 | 871531,0.0000033 1295 | 871539,0.0000033 1296 | 871555,0.000006 1297 | 871584,0.000006 1298 | 871646,0.000006 1299 | 871729,0.00000673 1300 | 871743,0.000006 1301 | 871754,0.000006 1302 | 871757,0.000006 1303 | 871791,0.0000033 1304 | 871792,0.0000033 1305 | 871797,0.0000033 1306 | 871799,0.000006 1307 | 871801,0.0000066 1308 | 871829,0.000006 1309 | 871830,0.000006 1310 | 871839,0.000006 1311 | 871870,0.0000099 1312 | 871882,0.000006 1313 | 871930,0.000006 1314 | 871944,0.000006 1315 | 871966,0.000006 1316 | 871976,0.0000033 1317 | 871982,0.000006 1318 | 872009,0.000096 1319 | 872013,0.0000066 1320 | 872029,0.000006 1321 | 872039,0.000006 1322 | 872045,0.0000033 1323 | 872070,0.0000093 1324 | 872078,0.000006 1325 | 872104,0.000006 1326 | 872162,0.000006 1327 | 872167,0.000006 1328 | 872176,0.0000033 1329 | 872191,0.000006 1330 | 872195,0.0000033 1331 | 872228,0.000006 1332 | 872230,0.0000033 1333 | 872238,0.000006 1334 | 872243,0.0000033 1335 | 872245,0.000006 1336 | 872268,0.000012 1337 | 872344,0.0000033 1338 | 872357,0.000006 1339 | 872359,0.0000033 1340 | 872374,0.0000033 1341 | 872392,0.000006 1342 | 872431,0.0000093 1343 | 872437,0.000006 1344 | 872450,0.000006 1345 | 872496,0.0000033 1346 | 872504,0.0000033 1347 | 872506,0.000012 1348 | 872546,0.0000093 1349 | 872579,0.000006 1350 | 872590,0.000006 1351 | 872622,0.0000033 1352 | 872659,0.0000033 1353 | 872697,0.0000033 1354 | 872703,0.0000033 1355 | 872727,0.000012 1356 | 872751,0.000006 1357 | 872755,0.000006 1358 | 872797,0.0000033 1359 | 872851,0.000006 1360 | 872878,0.0000033 1361 | 872958,0.0000033 1362 | 872976,0.0000033 1363 | 872998,0.000006 1364 | 873000,0.000006 1365 | 873019,0.000006 1366 | 873073,0.000006 1367 | 873118,0.000012 1368 | 873128,0.0000033 1369 | 873154,0.000006 1370 | 873157,0.0000033 1371 | 873160,0.0000033 1372 | 873204,0.000006 1373 | 873270,0.000006 1374 | 873307,0.0000033 1375 | 873340,0.000006 1376 | 873343,0.0000033 1377 | 873350,0.0000132 1378 | 873361,0.000006 1379 | 873369,0.000006 1380 | 873374,0.0000033 1381 | 873378,0.0000033 1382 | 873382,0.000006 1383 | 873383,0.0000033 1384 | 873387,0.0000033 1385 | 873390,0.000006 1386 | 873401,0.000006 1387 | 873414,0.0000033 1388 | 873454,0.000006 1389 | 873462,0.000006 1390 | 873478,0.000006 1391 | 873501,0.0000033 1392 | 873505,0.0000033 1393 | 873521,0.000006 1394 | 873574,0.0000093 1395 | 873581,0.0000033 1396 | 873634,0.000006 1397 | 873649,0.000006 1398 | 873681,0.000012 1399 | 873806,0.0000093 1400 | 873842,0.000006 1401 | 873894,0.000006 1402 | 873945,0.000006 1403 | 873956,0.000006 1404 | 873973,0.0000033 1405 | 873974,0.000006 1406 | 873985,0.0000033 1407 | 874026,0.000006 1408 | 874063,0.000006 1409 | 874077,0.0000033 1410 | 874094,0.000006 1411 | 874124,0.000006 1412 | 874127,0.0000033 1413 | 874159,0.0000099 1414 | 874167,0.000006 1415 | 874232,0.0000033 1416 | 874253,0.000006 1417 | 874270,0.0000033 1418 | 874274,0.000006 1419 | 874275,0.000006 1420 | 874360,0.000006 1421 | 874395,0.0000033 1422 | 874460,0.000012 1423 | 874528,0.000012 1424 | 874541,0.0000033 1425 | 874565,0.000006 1426 | 874635,0.000006 1427 | 874656,0.0000033 1428 | 874659,0.000006 1429 | 874763,0.000006 1430 | 874782,0.0000033 1431 | 874796,0.000006 1432 | 874824,0.0000033 1433 | 874866,0.0000033 1434 | 874879,0.000006 1435 | 874911,0.0000033 1436 | 874956,0.000006 1437 | 874981,0.000006 1438 | 875010,0.000006 1439 | 875045,0.0000033 1440 | 875073,0.000006 1441 | 875103,0.000006 1442 | 875146,0.000006 1443 | 875149,0.000006 1444 | 875214,0.000006 1445 | 875301,0.000006 1446 | 875342,0.000006 1447 | 875345,0.000006 1448 | 875351,0.000006 1449 | 875363,0.000006 1450 | 875391,0.0000033 1451 | 875463,0.0000033 1452 | 875483,0.0000033 1453 | 875488,0.000006 1454 | 875496,0.0000033 1455 | 875500,0.000012 1456 | 875502,0.0000033 1457 | 875564,0.0000033 1458 | 875565,0.000006 1459 | 875574,0.000006 1460 | 875580,0.000006 1461 | 875584,0.0000033 1462 | 875607,0.000006 1463 | 875651,0.000006 1464 | 875709,0.000006 1465 | 875713,0.000006 1466 | 875786,0.0000033 1467 | 875826,0.0000033 1468 | 875960,0.000006 1469 | 876026,0.000006 1470 | 876047,0.0000033 1471 | 876053,0.000006 1472 | 876092,0.0000033 1473 | 876113,0.000012 1474 | 876123,0.000006 1475 | 876135,0.000006 1476 | 876149,0.0000093 1477 | 876168,0.000006 1478 | 876176,0.0000033 1479 | 876187,0.000006 1480 | 876198,0.0000033 1481 | 876223,0.0000033 1482 | 876257,0.0000033 1483 | 876301,0.000012 1484 | 876307,0.000006 1485 | 876343,0.000006 1486 | 876376,0.000006 1487 | 876397,0.000006 1488 | 876428,0.000006 1489 | 876440,0.0000033 1490 | 876476,0.000012 1491 | 876558,0.000006 1492 | 876606,0.0000033 1493 | 876632,0.0000033 1494 | 876655,0.000012 1495 | 876740,0.000006 1496 | 876745,0.000006 1497 | 876782,0.000012 1498 | 876787,0.0000033 1499 | 876794,0.0000033 1500 | 876810,0.000006 1501 | 876868,0.0000033 1502 | 876869,0.0000033 1503 | 876887,0.0000033 1504 | 876903,0.0000033 1505 | 876920,0.000006 1506 | 876924,0.000006 1507 | 876938,0.0000033 1508 | 876940,0.000006 1509 | 876941,0.0000033 1510 | 876968,0.000006 1511 | 876979,0.000006 1512 | 876988,0.0000033 1513 | 876991,0.0000033 1514 | 877028,0.0000033 1515 | 877030,0.0000033 1516 | 877049,0.0000033 1517 | 877066,0.0000033 1518 | 877071,0.000006 1519 | 877074,0.0000153 1520 | 877075,0.0000033 1521 | 877077,0.000006 1522 | 877104,0.0000033 1523 | 877108,0.000006 1524 | 877146,0.0000033 1525 | 877159,0.000006 1526 | 877167,0.0000033 1527 | 877170,0.0000033 1528 | 877200,0.000006 1529 | 877210,0.000006 1530 | 877213,0.000018 1531 | 877214,0.000006 1532 | 877221,0.000006 1533 | 877223,0.000006 1534 | 877233,0.0000066 1535 | 877236,0.000006 1536 | 877240,0.000006 1537 | 877246,0.000012 1538 | 877253,0.000006 1539 | 877266,0.000006 1540 | 877269,0.0000033 1541 | 877272,0.000006 1542 | 877354,0.000006 1543 | 877365,0.0000066 1544 | 877368,0.000006 1545 | 877387,0.0000033 1546 | 877393,0.0000033 1547 | 877426,0.000012 1548 | 877435,0.0000033 1549 | 877468,0.000006 1550 | 877480,0.000006 1551 | 877542,0.000006 1552 | 877547,0.000006 1553 | 877548,0.000006 1554 | 877554,0.000006 1555 | 877561,0.0000033 1556 | 877589,0.0000033 1557 | 877648,0.000006 1558 | 877650,0.0000033 1559 | 877663,0.000006 1560 | 877671,0.0000033 1561 | 877673,0.0000033 1562 | 877724,0.000012 1563 | 877767,0.0000033 1564 | 877816,0.0000033 1565 | 877817,0.0000033 1566 | 877833,0.0000033 1567 | 877884,0.000006 1568 | 877908,0.000006 1569 | 877914,0.000006 1570 | 877918,0.000006 1571 | 877929,0.0000033 1572 | 877948,0.0000033 1573 | 877960,0.0000033 1574 | 877963,0.0000093 1575 | 877988,0.0000033 1576 | 877992,0.0000033 1577 | 878000,0.0000033 1578 | 878023,0.0000033 1579 | 878024,0.000006 1580 | 878036,0.0000033 1581 | 878041,0.0000033 1582 | 878069,0.000006 1583 | 878089,0.0000033 1584 | 878097,0.000006 1585 | 878106,0.000006 1586 | 878129,0.0000033 1587 | 878143,0.0000033 1588 | 878186,0.000006 1589 | 878188,0.000006 1590 | 878232,0.000012 1591 | 878235,0.000006 1592 | 878238,0.000006 1593 | 878259,0.0000033 1594 | 878280,0.0000033 1595 | 878298,0.0000033 1596 | 878313,0.0000033 1597 | 878334,0.0000033 1598 | 878337,0.0000033 1599 | 878338,0.0000033 1600 | 878341,0.000006 1601 | 878346,0.000006 1602 | 878376,0.0000033 1603 | 878384,0.0000033 1604 | 878390,0.0000033 1605 | 878406,0.0000033 1606 | 878462,0.0000033 1607 | 878474,0.000006 1608 | 878489,0.000006 1609 | 878492,0.000006 1610 | 878505,0.000006 1611 | 878512,0.0000033 1612 | 878514,0.0000033 1613 | 878517,0.000006 1614 | 878521,0.000006 1615 | 878533,0.000006 1616 | 878546,0.000006 1617 | 878552,0.0000033 1618 | 878583,0.000006 1619 | 878592,0.000006 1620 | 878603,0.000006 1621 | 878616,0.0000033 1622 | 878624,0.000006 1623 | 878629,0.0000033 1624 | 878631,0.0000033 1625 | 878640,0.0000033 1626 | 878676,0.0000033 1627 | 878698,0.000006 1628 | 878710,0.0000066 1629 | 878780,0.000006 1630 | 878786,0.0000033 1631 | 878847,0.0000033 1632 | 878850,0.0000033 1633 | 878894,0.000006 1634 | 878924,0.0000033 1635 | 878926,0.000006 1636 | 878929,0.0000033 1637 | 878933,0.0000159 1638 | 878946,0.0000033 1639 | 878951,0.0000033 1640 | 878952,0.0000033 1641 | 878970,0.000018 1642 | 878971,0.000042 1643 | 878972,0.000078 1644 | 878973,0.0000633 1645 | 878975,0.0000033 1646 | 878976,0.0000297 1647 | 878977,0.0000726 1648 | 878978,0.000033 1649 | 878979,0.0000726 1650 | 878980,0.0000759 1651 | 878991,0.0000033 1652 | 879006,0.000486 1653 | 879007,0.0142260 1654 | 879008,0.03055199 1655 | 879011,0.001422 1656 | 879015,0.002706 1657 | 879016,0.0240081 1658 | 879020,0.0010248 1659 | 879040,0.000006 1660 | 879076,0.0000033 1661 | 879095,0.0000033 1662 | 879110,0.0000033 1663 | 879141,0.0002319 1664 | 879142,0.0012663 1665 | 879145,0.0007326 1666 | 879146,0.0000627 1667 | 879151,0.0001287 1668 | 879152,0.00015 1669 | 879153,0.0000693 1670 | 879156,0.0004356 1671 | 879157,0.0007062 1672 | 879158,0.0001551 1673 | 879160,0.0010626 1674 | 879161,0.0005148 1675 | 879162,0.0002904 1676 | 879163,0.0013629 1677 | 879165,0.0009009 1678 | 879168,0.0002739 1679 | 879177,0.0000033 1680 | 879179,0.0000429 1681 | 879180,0.0000165 1682 | 879183,0.0000957 1683 | 879186,0.0000627 1684 | 879189,0.0003498 1685 | 879190,0.0001485 1686 | 879191,0.0000429 1687 | 879192,0.0000231 1688 | 879193,0.0000066 1689 | 879194,0.0000693 1690 | 879196,0.000006 1691 | 879197,0.0000132 1692 | 879198,0.0003228 1693 | 879200,0.000012 1694 | 879203,0.0000264 1695 | 879204,0.0008415 1696 | 879208,0.0002112 1697 | 879209,0.0001512 1698 | 879210,0.0005412 1699 | 879213,0.0013398 1700 | 879215,0.0012078 1701 | 879238,0.0008844 1702 | 879239,0.0000033 1703 | 879242,0.0003366 1704 | 879243,0.0000693 1705 | 879251,0.0007788 1706 | 879254,0.0000033 1707 | 879264,0.0001737 1708 | 879266,0.0003237 1709 | 879267,0.0014355 1710 | 879268,0.0014421 1711 | 879269,0.0016665 1712 | 879279,0.0006039 1713 | 879280,0.000396 1714 | 879281,0.0000924 1715 | 879282,0.0005544 1716 | 879283,0.0007359 1717 | 879284,0.0008118 1718 | 879287,0.0006369 1719 | 879288,0.0006831 1720 | 879290,0.0001188 1721 | 879293,0.0001782 1722 | 879294,0.0001617 1723 | 879295,0.0002541 1724 | 879297,0.0004125 1725 | 879298,0.0015444 1726 | 879299,0.0006105 1727 | 879302,0.0011121 1728 | 879303,0.0006699 1729 | 879310,0.0000033 1730 | 879311,0.0000132 1731 | 879312,0.0004488 1732 | 879315,0.000066 1733 | 879325,0.0004125 1734 | 879326,0.0000363 1735 | 879327,0.0001122 1736 | 879328,0.0004719 1737 | 879331,0.0000033 1738 | 879333,0.000561 1739 | 879334,0.0005742 1740 | 879402,0.0000033 1741 | 879430,0.0000033 1742 | 879434,0.0000033 1743 | 879443,0.0000033 1744 | 879451,0.000006 1745 | 879454,0.0000033 1746 | 879509,0.000006 1747 | 879515,0.000006 1748 | 879538,0.0000033 1749 | 879577,0.0000033 1750 | 879578,0.0000033 1751 | 879608,0.0001782 1752 | 879614,0.0002871 1753 | 879615,0.000429 1754 | 879616,0.0000033 1755 | 879643,0.0000033 1756 | 879655,0.0000093 1757 | 879677,0.000006 1758 | 879695,0.0000033 1759 | 879702,0.0004785 1760 | 879703,0.0000759 1761 | 879704,0.0002871 1762 | 879705,0.0006303 1763 | 879707,0.0005544 1764 | 879717,0.0000726 1765 | 879718,0.0005478 1766 | 879719,0.0002442 1767 | 879723,0.0002838 1768 | 879725,0.0001914 1769 | 879726,0.0002508 1770 | 879728,0.000264 1771 | 879730,0.0004884 1772 | 879731,0.0001815 1773 | 879732,0.0000264 1774 | 879733,0.0008877 1775 | 879734,0.0000099 1776 | 879735,0.0008712 1777 | 879736,0.0001353 1778 | 879737,0.0007062 1779 | 879738,0.0005478 1780 | 879739,0.0000132 1781 | 879740,0.000198 1782 | 879743,0.0001815 1783 | 879744,0.0008316 1784 | 879752,0.0007095 1785 | 879753,0.0001848 1786 | 879754,0.0002871 1787 | 879775,0.0000033 1788 | 879776,0.0000165 1789 | 879777,0.0004356 1790 | 879778,0.0000819 1791 | 879783,0.0003795 1792 | 879784,0.0002376 1793 | 879806,0.0000033 1794 | 879808,0.000006 1795 | 879828,0.0003432 1796 | 879829,0.0002832 1797 | 879831,0.0005412 1798 | 879832,0.0003927 1799 | 879835,0.0005928 1800 | 879843,0.0000297 1801 | 879844,0.0004125 1802 | 879845,0.0000429 1803 | 879846,0.0004983 1804 | 879848,0.0005181 1805 | 879849,0.0001584 1806 | 879850,0.0000429 1807 | 879851,0.0002442 1808 | 879852,0.0004026 1809 | 879853,0.0007788 1810 | 879854,0.0004224 1811 | 879856,0.0004224 1812 | 879857,0.0008811 1813 | 879858,0.0002376 1814 | 879859,0.0003795 1815 | 879860,0.0000033 1816 | 879861,0.0000792 1817 | 879862,0.0002574 1818 | 879863,0.0000825 1819 | 879864,0.0000099 1820 | 879867,0.0002607 1821 | 879868,0.0001353 1822 | 879869,0.0001749 1823 | 879870,0.0009009 1824 | 879871,0.0004785 1825 | 879872,0.0003993 1826 | 879873,0.0008646 1827 | 879874,0.0000594 1828 | 879875,0.0001188 1829 | 879876,0.0005709 1830 | 879877,0.0002046 1831 | 879878,0.000429 1832 | 879879,0.0005478 1833 | 879880,0.0002772 1834 | 879884,0.0000165 1835 | 879885,0.0000363 1836 | 879887,0.0000693 1837 | 879894,0.000006 1838 | 879899,0.0000033 1839 | 879901,0.0006699 1840 | 879943,0.000006 1841 | 879949,0.0004653 1842 | 879956,0.000132 1843 | 879965,0.0000726 1844 | 879978,0.000132 1845 | 879982,0.0000033 1846 | 879983,0.0003135 1847 | 879984,0.0003927 1848 | 879986,0.0000924 1849 | 879987,0.0000165 1850 | 879988,0.0003861 1851 | 879989,0.0003129 1852 | 879990,0.0004983 1853 | 879991,0.0000495 1854 | 879998,0.0000033 1855 | 880047,0.000006 1856 | 880129,0.000006 1857 | 880163,0.000006 1858 | 880213,0.000006 1859 | 880223,0.000006 1860 | 880265,0.000006 1861 | 880356,0.000006 1862 | 880446,0.000006 1863 | 880488,0.000006 1864 | 880516,0.000006 1865 | 880521,0.000012 1866 | 880629,0.000006 1867 | 880783,0.000006 1868 | 880893,0.00015 1869 | 880906,0.000006 1870 | 880933,0.000012 1871 | 880982,0.000006 1872 | 881003,0.000096 1873 | 881004,0.000174 1874 | 881006,0.00027 1875 | 881007,0.001614 1876 | 881009,0.000018 1877 | 881011,0.00075 1878 | 881012,0.00066 1879 | 881015,0.000354 1880 | 881016,0.000636 1881 | 881021,0.00036 1882 | 881027,0.000378 1883 | 881046,0.000006 1884 | 881050,0.00003 1885 | 881051,0.00054 1886 | 881060,0.000372 1887 | 881061,0.001278 1888 | 881063,0.001272 1889 | 881082,0.000006 1890 | 881088,0.000276 1891 | 881089,0.00159 1892 | 881090,0.000012 1893 | 881124,0.00057 1894 | 881126,0.00027 1895 | 881127,0.00054 1896 | 881130,0.000714 1897 | 881134,0.000894 1898 | 881136,0.001974 1899 | 881138,0.001428 1900 | 881139,0.000234 1901 | 881140,0.000084 1902 | 881141,0.000324 1903 | 881144,0.000018 1904 | 881145,0.000264 1905 | 881150,0.000144 1906 | 881151,0.00006 1907 | 881155,0.000096 1908 | 881156,0.001218 1909 | 881158,0.00072 1910 | 881159,0.002814 1911 | 881160,0.00081 1912 | 881161,0.000624 1913 | 881162,0.000522 1914 | 881163,0.000522 1915 | 881164,0.00162 1916 | 881167,0.001818 1917 | 881168,0.011244 1918 | 881169,0.023826 1919 | 881170,0.016602 1920 | 881172,0.000006 -------------------------------------------------------------------------------- /addressPoisonAttacks/addressPoisonTxnSize.csv: -------------------------------------------------------------------------------- 1 | 4374 2 | 1341 3 | 2108 4 | 192 5 | 192 6 | 191 7 | 192 8 | 192 9 | 192 10 | 192 11 | 958 12 | 191 13 | 192 14 | 192 15 | 192 16 | 382 17 | 192 18 | 192 19 | 192 20 | 191 21 | 192 22 | 192 23 | 192 24 | 192 25 | 191 26 | 192 27 | 192 28 | 191 29 | 192 30 | 192 31 | 191 32 | 574 33 | 191 34 | 191 35 | 191 36 | 192 37 | 192 38 | 191 39 | 191 40 | 192 41 | 192 42 | 191 43 | 192 44 | 191 45 | 191 46 | 192 47 | 191 48 | 190 49 | 192 50 | 383 51 | 191 52 | 191 53 | 191 54 | 191 55 | 191 56 | 192 57 | 192 58 | 191 59 | 191 60 | 192 61 | 192 62 | 191 63 | 191 64 | 192 65 | 192 66 | 191 67 | 192 68 | 192 69 | 191 70 | 191 71 | 192 72 | 191 73 | 191 74 | 191 75 | 191 76 | 192 77 | 383 78 | 192 79 | 192 80 | 191 81 | 192 82 | 191 83 | 191 84 | 192 85 | 191 86 | 191 87 | 191 88 | 191 89 | 191 90 | 192 91 | 384 92 | 191 93 | 192 94 | 191 95 | 192 96 | 191 97 | 191 98 | 192 99 | 192 100 | 766 101 | 192 102 | 192 103 | 192 104 | 191 105 | 191 106 | 191 107 | 192 108 | 191 109 | 382 110 | 191 111 | 192 112 | 192 113 | 192 114 | 191 115 | 573 116 | 191 117 | 191 118 | 191 119 | 192 120 | 192 121 | 192 122 | 192 123 | 192 124 | 191 125 | 192 126 | 192 127 | 192 128 | 192 129 | 191 130 | 191 131 | 191 132 | 191 133 | 192 134 | 191 135 | 766 136 | 382 137 | 192 138 | 191 139 | 192 140 | 191 141 | 192 142 | 192 143 | 192 144 | 192 145 | 192 146 | 192 147 | 192 148 | 191 149 | 192 150 | 191 151 | 192 152 | 191 153 | 192 154 | 191 155 | 191 156 | 191 157 | 192 158 | 192 159 | 383 160 | 192 161 | 192 162 | 191 163 | 192 164 | 192 165 | 192 166 | 191 167 | 192 168 | 192 169 | 192 170 | 192 171 | 192 172 | 191 173 | 192 174 | 192 175 | 191 176 | 191 177 | 191 178 | 191 179 | 191 180 | 192 181 | 382 182 | 191 183 | 191 184 | 192 185 | 192 186 | 191 187 | 192 188 | 191 189 | 191 190 | 382 191 | 191 192 | 191 193 | 192 194 | 191 195 | 1339 196 | 192 197 | 192 198 | 191 199 | 192 200 | 190 201 | 192 202 | 192 203 | 220 204 | 220 205 | 110 206 | 110 207 | 110 208 | 192 209 | 956 210 | 110 211 | 192 212 | 192 213 | 244 214 | 191 215 | 192 216 | 110 217 | 191 218 | 191 219 | 110 220 | 134 221 | 110 222 | 110 223 | 110 224 | 134 225 | 192 226 | 192 227 | 191 228 | 192 229 | 191 230 | 191 231 | 191 232 | 192 233 | 191 234 | 191 235 | 110 236 | 191 237 | 110 238 | 220 239 | 192 240 | 384 241 | 134 242 | 330 243 | 134 244 | 191 245 | 134 246 | 192 247 | 192 248 | 191 249 | 110 250 | 192 251 | 190 252 | 110 253 | 192 254 | 110 255 | 191 256 | 990 257 | 191 258 | 191 259 | 191 260 | 192 261 | 192 262 | 192 263 | 110 264 | 192 265 | 134 266 | 192 267 | 110 268 | 110 269 | 192 270 | 191 271 | 191 272 | 382 273 | 192 274 | 110 275 | 192 276 | 192 277 | 134 278 | 110 279 | 191 280 | 110 281 | 110 282 | 110 283 | 192 284 | 192 285 | 192 286 | 110 287 | 110 288 | 134 289 | 110 290 | 191 291 | 382 292 | 134 293 | 110 294 | 110 295 | 134 296 | 192 297 | 192 298 | 191 299 | 191 300 | 191 301 | 110 302 | 191 303 | 134 304 | 134 305 | 110 306 | 110 307 | 134 308 | 191 309 | 134 310 | 191 311 | 134 312 | 220 313 | 110 314 | 110 315 | 134 316 | 134 317 | 134 318 | 110 319 | 110 320 | 134 321 | 110 322 | 191 323 | 110 324 | 110 325 | 110 326 | 110 327 | 110 328 | 110 329 | 191 330 | 192 331 | 134 332 | 134 333 | 110 334 | 110 335 | 110 336 | 134 337 | 192 338 | 134 339 | 110 340 | 134 341 | 192 342 | 134 343 | 110 344 | 110 345 | 110 346 | 191 347 | 220 348 | 192 349 | 192 350 | 191 351 | 330 352 | 134 353 | 192 354 | 191 355 | 191 356 | 110 357 | 134 358 | 3067 359 | 220 360 | 192 361 | 192 362 | 110 363 | 244 364 | 191 365 | 191 366 | 192 367 | 134 368 | 110 369 | 192 370 | 110 371 | 134 372 | 110 373 | 192 374 | 110 375 | 191 376 | 268 377 | 110 378 | 191 379 | 110 380 | 110 381 | 192 382 | 302 383 | 192 384 | 191 385 | 110 386 | 110 387 | 268 388 | 301 389 | 191 390 | 134 391 | 110 392 | 110 393 | 110 394 | 110 395 | 382 396 | 134 397 | 134 398 | 110 399 | 192 400 | 110 401 | 110 402 | 110 403 | 134 404 | 134 405 | 192 406 | 134 407 | 383 408 | 110 409 | 134 410 | 110 411 | 110 412 | 191 413 | 192 414 | 110 415 | 190 416 | 110 417 | 440 418 | 192 419 | 134 420 | 110 421 | 110 422 | 192 423 | 110 424 | 110 425 | 192 426 | 191 427 | 110 428 | 191 429 | 134 430 | 134 431 | 110 432 | 110 433 | 134 434 | 302 435 | 110 436 | 134 437 | 191 438 | 382 439 | 244 440 | 134 441 | 192 442 | 134 443 | 134 444 | 110 445 | 134 446 | 110 447 | 134 448 | 134 449 | 110 450 | 192 451 | 134 452 | 110 453 | 330 454 | 191 455 | 110 456 | 192 457 | 110 458 | 134 459 | 134 460 | 191 461 | 110 462 | 384 463 | 268 464 | 110 465 | 134 466 | 134 467 | 110 468 | 191 469 | 134 470 | 110 471 | 192 472 | 110 473 | 110 474 | 192 475 | 110 476 | 191 477 | 134 478 | 134 479 | 110 480 | 134 481 | 134 482 | 133 483 | 191 484 | 134 485 | 134 486 | 134 487 | 134 488 | 134 489 | 191 490 | 110 491 | 110 492 | 110 493 | 134 494 | 110 495 | 268 496 | 110 497 | 110 498 | 134 499 | 192 500 | 192 501 | 110 502 | 134 503 | 192 504 | 134 505 | 134 506 | 110 507 | 110 508 | 134 509 | 134 510 | 110 511 | 191 512 | 110 513 | 268 514 | 134 515 | 192 516 | 244 517 | 134 518 | 110 519 | 191 520 | 110 521 | 110 522 | 110 523 | 383 524 | 134 525 | 134 526 | 134 527 | 134 528 | 192 529 | 110 530 | 268 531 | 191 532 | 110 533 | 110 534 | 268 535 | 134 536 | 192 537 | 383 538 | 110 539 | 110 540 | 191 541 | 110 542 | 110 543 | 110 544 | 110 545 | 192 546 | 134 547 | 110 548 | 134 549 | 110 550 | 134 551 | 134 552 | 110 553 | 110 554 | 110 555 | 110 556 | 110 557 | 110 558 | 191 559 | 436 560 | 110 561 | 134 562 | 110 563 | 134 564 | 110 565 | 191 566 | 110 567 | 110 568 | 134 569 | 192 570 | 402 571 | 134 572 | 134 573 | 134 574 | 220 575 | 134 576 | 134 577 | 384 578 | 134 579 | 134 580 | 110 581 | 134 582 | 191 583 | 220 584 | 191 585 | 110 586 | 110 587 | 268 588 | 110 589 | 134 590 | 134 591 | 134 592 | 192 593 | 134 594 | 134 595 | 110 596 | 110 597 | 191 598 | 110 599 | 134 600 | 110 601 | 110 602 | 268 603 | 110 604 | 110 605 | 110 606 | 110 607 | 192 608 | 192 609 | 192 610 | 134 611 | 110 612 | 110 613 | 110 614 | 302 615 | 110 616 | 110 617 | 110 618 | 110 619 | 134 620 | 110 621 | 110 622 | 191 623 | 110 624 | 134 625 | 134 626 | 110 627 | 110 628 | 134 629 | 192 630 | 383 631 | 134 632 | 134 633 | 110 634 | 110 635 | 110 636 | 110 637 | 110 638 | 110 639 | 110 640 | 191 641 | 134 642 | 110 643 | 110 644 | 110 645 | 110 646 | 110 647 | 134 648 | 134 649 | 191 650 | 192 651 | 110 652 | 110 653 | 191 654 | 134 655 | 191 656 | 134 657 | 110 658 | 134 659 | 134 660 | 134 661 | 110 662 | 192 663 | 110 664 | 110 665 | 110 666 | 110 667 | 134 668 | 220 669 | 191 670 | 110 671 | 110 672 | 110 673 | 191 674 | 109 675 | 133 676 | 109 677 | 460 678 | 110 679 | 110 680 | 110 681 | 399 682 | 931 683 | 1729 684 | 1439 685 | 109 686 | 981 687 | 2398 688 | 1090 689 | 2398 690 | 2507 691 | 110 692 | 10854 693 | 317714 694 | 682328 695 | 31758 696 | 60434 697 | 708860 698 | 29276 699 | 192 700 | 110 701 | 110 702 | 110 703 | 6740 704 | 39570 705 | 24420 706 | 2090 707 | 4290 708 | 4802 709 | 2310 710 | 14520 711 | 23540 712 | 5170 713 | 35420 714 | 17160 715 | 9680 716 | 45430 717 | 30030 718 | 9130 719 | 110 720 | 1430 721 | 550 722 | 3190 723 | 2090 724 | 11660 725 | 4950 726 | 1430 727 | 770 728 | 220 729 | 2310 730 | 192 731 | 440 732 | 10694 733 | 383 734 | 880 735 | 28050 736 | 7040 737 | 4974 738 | 18040 739 | 44660 740 | 40260 741 | 29480 742 | 110 743 | 11220 744 | 2310 745 | 25960 746 | 110 747 | 5658 748 | 10460 749 | 47850 750 | 48070 751 | 55550 752 | 20130 753 | 13200 754 | 3080 755 | 18480 756 | 24530 757 | 27060 758 | 21230 759 | 22770 760 | 3960 761 | 5940 762 | 5390 763 | 8470 764 | 13750 765 | 51480 766 | 20350 767 | 37070 768 | 22330 769 | 110 770 | 440 771 | 14960 772 | 2200 773 | 13750 774 | 1210 775 | 3740 776 | 15730 777 | 110 778 | 18700 779 | 19140 780 | 110 781 | 110 782 | 110 783 | 110 784 | 191 785 | 110 786 | 191 787 | 192 788 | 110 789 | 110 790 | 110 791 | 5940 792 | 9570 793 | 14300 794 | 110 795 | 110 796 | 302 797 | 192 798 | 110 799 | 15950 800 | 2530 801 | 9570 802 | 21010 803 | 18480 804 | 2420 805 | 18260 806 | 8140 807 | 9460 808 | 6380 809 | 8360 810 | 8800 811 | 16280 812 | 6050 813 | 880 814 | 29590 815 | 330 816 | 29040 817 | 4510 818 | 23540 819 | 18260 820 | 440 821 | 6600 822 | 6050 823 | 27720 824 | 23650 825 | 6160 826 | 9570 827 | 110 828 | 550 829 | 14520 830 | 2722 831 | 12650 832 | 7920 833 | 110 834 | 192 835 | 11440 836 | 9432 837 | 18040 838 | 13090 839 | 19743 840 | 990 841 | 13750 842 | 1430 843 | 16610 844 | 17270 845 | 5280 846 | 1430 847 | 8140 848 | 13420 849 | 25960 850 | 14080 851 | 14080 852 | 29370 853 | 7920 854 | 12650 855 | 110 856 | 2640 857 | 8580 858 | 2750 859 | 330 860 | 8690 861 | 4510 862 | 5830 863 | 30030 864 | 15950 865 | 13310 866 | 28820 867 | 1980 868 | 3960 869 | 19030 870 | 6820 871 | 14300 872 | 18260 873 | 9240 874 | 550 875 | 1210 876 | 2310 877 | 191 878 | 110 879 | 22330 880 | 192 881 | 15510 882 | 4400 883 | 2420 884 | 4400 885 | 110 886 | 10450 887 | 13090 888 | 3080 889 | 550 890 | 12870 891 | 10422 892 | 16610 893 | 1650 894 | 110 895 | 191 896 | 192 897 | 192 898 | 191 899 | 192 900 | 191 901 | 192 902 | 192 903 | 191 904 | 192 905 | 384 906 | 192 907 | 192 908 | 4750 909 | 190 910 | 380 911 | 190 912 | 3056 913 | 5539 914 | 8595 915 | 51379 916 | 573 917 | 23875 918 | 21010 919 | 11269 920 | 20246 921 | 11460 922 | 12033 923 | 192 924 | 950 925 | 17190 926 | 11842 927 | 40683 928 | 40492 929 | 192 930 | 8786 931 | 50615 932 | 382 933 | 18145 934 | 8595 935 | 17190 936 | 22729 937 | 28459 938 | 62839 939 | 45458 940 | 7449 941 | 2660 942 | 10314 943 | 573 944 | 8404 945 | 4584 946 | 1900 947 | 3056 948 | 38774 949 | 22920 950 | 89579 951 | 25785 952 | 19864 953 | 16617 954 | 16617 955 | 51570 956 | 57873 957 | 357934 958 | 762432 959 | 531264 960 | 192 -------------------------------------------------------------------------------- /addressPoisonAttacks/findAddressPoisonDetails.php: -------------------------------------------------------------------------------- 1 | getRawTransaction($txid, 2)->get(); 24 | // extract the target victim address 25 | $address = $transaction['vout'][0]['scriptPubKey']['address']; 26 | echo $data[0] . ',' . $address . "\n"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /addressPoisonAttacks/findAddressPoisonTransactions.php: -------------------------------------------------------------------------------- 1 | getBlockchaininfo()->get('blocks'); 10 | $heightRange = $maxBlockHeight - $height; 11 | $spamBlockHeights = array(); 12 | $spamBlockValues = array(); 13 | $spamBlockFees = array(); 14 | $spamBlockSize = array(); 15 | 16 | // example 1 https://mempool.space/tx/7e9fc6393f24e6d574bfce8c19aac20c1be3c5171a818afb9701483cd3eb5c30 17 | // example 2 https://mempool.space/tx/eb692afae43f8246f1b60657271d37e4a4ab183ae542aa7452fa49b2359cf839 18 | 19 | // initialize start block vars 20 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 21 | $block = $bitcoind->getBlock($currentBlockHash, 2); 22 | $height++; 23 | 24 | function set_precision($value) { 25 | return sprintf('%.8F',$value); 26 | } 27 | 28 | while ($height < $maxBlockHeight) { 29 | $block = $bitcoind->getBlock($block->get('nextblockhash'), 2); 30 | 31 | foreach ($block->get('tx') as $transaction) { 32 | // 1-input, 1-output transaction with low values are suspicious 33 | if (count($transaction['vin']) == 1 && count($transaction['vout']) == 1 && set_precision(floatval($transaction['vout'][0]['value'])) < 0.00001000) { 34 | // ignore taproot inscriptions 35 | if (isset($transaction['vin'][0]['txinwitness']) && count($transaction['vin'][0]['txinwitness']) == 3) { 36 | continue; 37 | } 38 | // ignore OP_RETURN outputs 39 | if(!isset($transaction['vout'][0]['scriptPubKey']['address'])) { 40 | continue; 41 | } 42 | 43 | $transaction = $bitcoind->getRawtransaction($transaction['txid'], 2)->get(); 44 | 45 | // ignore if it's the exact same address 46 | if ($transaction['vin'][0]['prevout']['scriptPubKey']['address'] == $transaction['vout'][0]['scriptPubKey']['address']) { 47 | continue; 48 | } 49 | 50 | // is it address poisoning? 51 | if (isset($transaction['vin'][0]['prevout']['scriptPubKey']['address']) && isset($transaction['vout'][0]['scriptPubKey']['address']) 52 | && substr($transaction['vin'][0]['prevout']['scriptPubKey']['address'], 0, 3) == substr($transaction['vout'][0]['scriptPubKey']['address'], 0, 3) 53 | && substr($transaction['vin'][0]['prevout']['scriptPubKey']['address'], -4) == substr($transaction['vout'][0]['scriptPubKey']['address'], -4)) { 54 | echo "$height " . $transaction['txid'] . " " . $transaction['vin'][0]['prevout']['scriptPubKey']['address'] . " " . $transaction['vout'][0]['value'] . "\n"; 55 | } else { 56 | continue; 57 | } 58 | } else { 59 | continue; 60 | } 61 | 62 | // If we got this far, consider this transaction to be spam 63 | if (isset($spamBlockHeights[$height])) { 64 | $spamBlockHeights[$height]++; 65 | } else { 66 | $spamBlockHeights[$height] = 1; 67 | } 68 | 69 | if (isset($spamBlockSize[$height])) { 70 | $spamBlockSize[$height] += $transaction['vsize']; 71 | } else { 72 | $spamBlockSize[$height] = $transaction['vsize']; 73 | } 74 | 75 | if (isset($spamBlockFees[$height])) { 76 | $spamBlockFees[$height] += $transaction['fee']; 77 | } else { 78 | $spamBlockFees[$height] = $transaction['fee']; 79 | } 80 | 81 | // Calculate total spammy output values 82 | foreach ($transaction['vout'] as $vout) { 83 | if (isset($spamBlockValues[$height])) { 84 | $spamBlockValues[$height] += $vout['value']; 85 | } else { 86 | $spamBlockValues[$height] = $vout['value']; 87 | } 88 | } 89 | } 90 | 91 | if ($height % 1000 == 0) { 92 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 93 | echo "$complete%\n"; 94 | } 95 | $height++; 96 | } 97 | 98 | // sort by block height ascending 99 | ksort($spamBlockHeights); 100 | 101 | echo "Block Height,Spam Txns:\n"; 102 | foreach ($spamBlockHeights as $height => $count) { 103 | echo "$height,$count\n"; 104 | } 105 | 106 | // sort by block height ascending 107 | ksort($spamBlockSize); 108 | 109 | echo "Block Height,Spam Txn Size:\n"; 110 | foreach ($spamBlockSize as $height => $size) { 111 | echo "$height,$size\n"; 112 | } 113 | 114 | // sort by block height ascending 115 | ksort($spamBlockFees); 116 | 117 | echo "Block Height,Spam Txn Fees:\n"; 118 | foreach ($spamBlockFees as $height => $fees) { 119 | echo "$height," . set_precision($fees) . "\n"; 120 | } 121 | 122 | // sort by block height ascending 123 | ksort($spamBlockValues); 124 | 125 | echo "Block Height,Spam Txn value:\n"; 126 | foreach ($spamBlockValues as $height => $value) { 127 | echo "$height,$value\n"; 128 | } 129 | -------------------------------------------------------------------------------- /addressPoisonAttacks/findSuccessfulAttacks.php: -------------------------------------------------------------------------------- 1 | 2) { 25 | // sum up the total of all deposits to the attacker address 26 | $deposits = 0; 27 | foreach ($result as $txn) { 28 | foreach ($txn->vout as $out) { 29 | if (isset($out->scriptpubkey_address) && $out->scriptpubkey_address == $address) { 30 | $deposits += $out->value; 31 | } 32 | } 33 | } 34 | if ($deposits > 20000) { 35 | echo "$address,$deposits\n"; 36 | } 37 | } 38 | } catch (Exception $e) { 39 | echo "Error getting txn history for $address\n"; 40 | } 41 | $processed++; 42 | if ($processed % 1000 == 0) { 43 | echo "processed $processed\n"; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /addressPoisonAttacks/getTargetAddressDetails.php: -------------------------------------------------------------------------------- 1 | chain_stats) || $result->chain_stats->funded_txo_sum == 0 || $result->chain_stats->funded_txo_count == 0) { 23 | continue; 24 | } 25 | $avgDeposit = ($result->chain_stats->funded_txo_sum / $result->chain_stats->funded_txo_count) / 100000000; 26 | $avgWithdrawal = 0; 27 | if ($result->chain_stats->spent_txo_count > 0) { 28 | $avgWithdrawal = ($result->chain_stats->spent_txo_sum / $result->chain_stats->spent_txo_count) / 100000000; 29 | } 30 | echo $address . "," . $result->chain_stats->funded_txo_count . ",$avgDeposit," . $result->chain_stats->spent_txo_count . ",$avgWithdrawal,"; 31 | 32 | // get transaction details 33 | curl_setopt($ch, CURLOPT_URL, "https://blockstream.info/api/address/$address/txs"); 34 | $result = json_decode(curl_exec($ch)); 35 | try { 36 | if ($result == null) { 37 | echo " Unknown history for $address\n"; 38 | } else { 39 | $newestTxn = $result[0]; 40 | $oldestTxn = array_pop($result); 41 | 42 | curl_setopt($ch, CURLOPT_URL, "https://blockstream.info/api/tx/" . $oldestTxn->txid); 43 | $result = json_decode(curl_exec($ch)); 44 | if ($result->status == null or !isset($result->status->block_time)) { 45 | echo "\n"; 46 | continue; 47 | } 48 | $date = date('Y-m-d', $result->status->block_time); 49 | echo "$date,"; 50 | 51 | curl_setopt($ch, CURLOPT_URL, "https://blockstream.info/api/tx/" . $newestTxn->txid); 52 | $result = json_decode(curl_exec($ch)); 53 | if ($result->status == null or !isset($result->status->block_time)) { 54 | echo "\n"; 55 | continue; 56 | } 57 | $date = date('Y-m-d', $result->status->block_time); 58 | echo "$date\n"; 59 | } 60 | } catch (Exception $e) { 61 | echo "Error getting txn history for $address\n"; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /address_watcher.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This utility script checks the balance of the configured bitcoin addresses every 10 minutes 3 | # and, if the balance changes, sends an alert email to the configured address 4 | 5 | btc_addresses=( 12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX 1FfmbHfnpaZjKFvyi1okTjJJusN455paPH ) 6 | email_address='your.email@domain.com' 7 | 8 | # initialize balances 9 | btc_balances=() 10 | for (( i = 0; i < ${#btc_addresses[@]}; i++ )); do 11 | btc_balances[i]=$(curl -s https://blockchain.info/q/addressbalance/${btc_addresses[$i]}) 12 | sleep 10 # respect blockchain.info API rate limit guidelines 13 | done 14 | 15 | # daemon 16 | while [ true ]; do 17 | sleep 600 # only check addresses balances once per ~block 18 | 19 | # check the balance of each address 20 | for (( i = 0; i < ${#btc_addresses[@]}; i++ )); do 21 | new_balance=$(curl -s https://blockchain.info/q/addressbalance/${btc_addresses[$i]}) 22 | 23 | if [ $new_balance -ne ${btc_balances[$i]} ]; then 24 | old_formatted=$(echo "${btc_balances[$i]}/100000000" | bc -l | sed 's/0*$//') 25 | new_formatted=$(echo "$new_balance/100000000" | bc -l | sed 's/0*$//') 26 | mail -s "BTC Transaction Alert" $email_address <<< "The balance of ${btc_addresses[$i]} has changed from $old_formatted to $new_formatted BTC!" 27 | btc_balances[i]=$new_balance 28 | fi 29 | sleep 10 30 | done 31 | done 32 | -------------------------------------------------------------------------------- /bsv_twitter_accounts/extractBSVTwitterAccounts.php: -------------------------------------------------------------------------------- 1 | 1) { 13 | echo "ERROR: second argument must be a decimal between 0 and 1\n"; 14 | exit; 15 | } 16 | 17 | $threshold = $argv[2]; 18 | 19 | echo "Account ID,Account Handle\n"; 20 | if (($handle = fopen($argv[1], "r")) !== FALSE) { 21 | // skip first row 22 | fgetcsv($handle, 1000, ","); 23 | 24 | while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 25 | if (isset($data[12]) && isset($data[13]) && isset($data[17])) { 26 | if ($data[12] >= $threshold && $data[13] >= $threshold && ($data[16] >= 0.15 || $data[17] >= 0.15)) { 27 | // filter out BCH handles 28 | if (stristr($data[3], "bch") || stristr($data[3], "bitcoincash")) { 29 | continue; 30 | } 31 | echo $data[1] . "," . $data[3] . "\n"; 32 | } 33 | } 34 | } 35 | fclose($handle); 36 | } else { 37 | echo "ERROR: Failed to open CSV file\n"; 38 | } -------------------------------------------------------------------------------- /checkTransactions.php: -------------------------------------------------------------------------------- 1 | getRawtransaction($txHash, true)->get(); 28 | } catch (Exception $error) { 29 | echo "ERROR: tx hash $txHash does not exist!\n"; 30 | continue; 31 | } 32 | 33 | // Calculate transaction fee paid (aggregate output value - aggregate input value) 34 | $inputValue = $outputValue = 0; 35 | foreach ($transaction['vin'] as $input) { 36 | $inputTx = $bitcoind->getRawtransaction($input['txid'], true)->get(); 37 | $inputValue += $inputTx['vout'][$input['vout']]['value']; 38 | } 39 | foreach ($transaction['vout'] as $output) { 40 | $outputValue += $output['value']; 41 | } 42 | $fee = round(($inputValue - $outputValue) * 100_000_000); 43 | 44 | if ($txFee != $fee) { 45 | echo "ERROR: $txHash expected tx fee $txFee, got $fee \n"; 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /countBitcoinIRCActivity.php: -------------------------------------------------------------------------------- 1 | format("Y-m-d")); 20 | $result = curl_exec($ch); 21 | $dayCount = substr_count($result, "talk op-msg"); 22 | 23 | if (isset($counts[$date->format("Y-m")])) { 24 | $counts[$date->format("Y-m")] += $dayCount; 25 | } else { 26 | $counts[$date->format("Y-m")] = $dayCount; 27 | } 28 | } 29 | 30 | 31 | // Sort and print the results 32 | $total = 0; 33 | ksort($counts); 34 | foreach ($counts as $month => $count) { 35 | echo "$month,$count\n"; 36 | } -------------------------------------------------------------------------------- /countBlocksPerDay.php: -------------------------------------------------------------------------------- 1 | getBlockChainInfo()->get('blocks'); 10 | $heightRange = $maxBlockHeight - $height; 11 | $dayCounts = array(); 12 | 13 | // initialize start block vars 14 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 15 | $block = $bitcoind->getBlockheader($currentBlockHash); 16 | $nextBlockHash = $block->get('nextblockhash'); 17 | 18 | while ($height < $maxBlockHeight) { 19 | $block = $bitcoind->getBlockheader($nextBlockHash); 20 | $timestamp = $block->get('time'); 21 | $dmy = gmdate("m-d-Y", $timestamp); 22 | if (key_exists($dmy, $dayCounts)) { 23 | $dayCounts[$dmy]++; 24 | } else { 25 | $dayCounts[$dmy] = 1; 26 | } 27 | 28 | if ($height % 1000 == 0) { 29 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 30 | echo "$complete%\n"; 31 | } 32 | 33 | $height++; 34 | $nextBlockHash = $block->get('nextblockhash'); 35 | } 36 | 37 | echo "Date,Blocks Mined\n"; 38 | foreach ($dayCounts as $date => $blocks) { 39 | echo "$date,$blocks\n"; 40 | } -------------------------------------------------------------------------------- /countCoinJoinTransactions.php: -------------------------------------------------------------------------------- 1 | getBlockchaininfo()->get('blocks'); 11 | $heightRange = $maxBlockHeight - $height; 12 | $txByBlock = array(); 13 | $wuByBlock = array(); 14 | 15 | // initialize start block vars 16 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 17 | $block = $bitcoind->getBlock($currentBlockHash, 2); 18 | $height++; 19 | 20 | while ($height < $maxBlockHeight) { 21 | $block = $bitcoind->getBlock($block->get('nextblockhash'), 2); 22 | $txByBlock[$height] = 0; 23 | $wuByBlock[$height] = 0; 24 | 25 | foreach ($block->get('tx') as $transaction) { 26 | if (count($transaction['vin']) >= 5 && count($transaction['vin']) == count($transaction['vout'])) { 27 | $txByBlock[$height]++; 28 | $wuByBlock[$height] += $transaction['weight']; 29 | } else if (count($transaction['vin']) >= 50 && count($transaction['vout']) >= 50) { 30 | $txByBlock[$height]++; 31 | $wuByBlock[$height] += $transaction['weight']; 32 | } 33 | } 34 | 35 | if ($height % 1000 == 0) { 36 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 37 | echo "$complete%\n"; 38 | } 39 | $height++; 40 | } 41 | 42 | ksort($txByBlock); 43 | 44 | echo "Block Height, CoinJoin Transactions, CoinJoin Weight Units\n"; 45 | foreach ($txByBlock as $height => $count) { 46 | echo "$height,$count," . $weByBlock[$height] . "\n"; 47 | } 48 | -------------------------------------------------------------------------------- /countReachableBitcoinPeers.php: -------------------------------------------------------------------------------- 1 | nodes as $node) { 18 | $count++; 19 | } 20 | $chunkSize = floor($count / 100); 21 | $rangeStart = $chunkSize * $argv[1]; 22 | $rangeEnd = $chunkSize * $argv[1] + $chunkSize; 23 | 24 | $count = 0; 25 | foreach ($snapshotJson->nodes as $nodeIP => $attributes) { 26 | if ($count >= $rangeStart && $count < $rangeEnd) { 27 | $chunkJson[$nodeIP] = $attributes; 28 | } 29 | $count++; 30 | } 31 | } else { 32 | $ch = curl_init(); 33 | curl_setopt($ch, CURLOPT_URL, "https://bitnodes.io/api/v1/snapshots/"); 34 | curl_setopt($ch, CURLOPT_HEADER, 0); 35 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 36 | 37 | $result = curl_exec($ch); 38 | $snapshotListJson = json_decode($result); 39 | $snapshotURL = $snapshotListJson->results[0]->url; 40 | curl_setopt($ch, CURLOPT_URL, $snapshotURL); 41 | 42 | $result = curl_exec($ch); 43 | file_put_contents("nodes.json", $result); 44 | echo "Wrote nodes snapshot json file to disk\n"; 45 | exit; 46 | } 47 | 48 | $totalNodes = $attemptedNodes = $reachableNodes = $unreachableNodes = $prunedNodes = 0; 49 | $blockDownloadFailed = $blockDownloadSucceeded = 0; 50 | $blockDownloadTimes = array(); 51 | 52 | foreach ($chunkJson as $nodeIP => $attributes) { 53 | $totalNodes++; 54 | } 55 | $percentOfNodes = floor($totalNodes / 100); 56 | 57 | foreach ($chunkJson as $nodeIP => $attributes) { 58 | $attemptedNodes++; 59 | if ($attemptedNodes % $percentOfNodes == 0) { 60 | echo floor(($attemptedNodes / $totalNodes) * 100) . "% COMPLETE\n"; 61 | } 62 | 63 | // 11 is ASN 64 | if ($attributes[11] == 'TOR') { 65 | continue; 66 | } 67 | 68 | // if node IP address includes bracket charts, it's IPV6 69 | if (strstr($nodeIP, '[') !== false) { 70 | continue; 71 | } 72 | 73 | //echo "connecting to $nodeIP\n"; 74 | 75 | // this is an IPV4 peer; attempt to connect 76 | $success = connectPeer(explode(":", $nodeIP)[0], explode(":", $nodeIP)[1]); 77 | if ($success) { 78 | $reachableNodes++; 79 | } else { 80 | $unreachableNodes++; 81 | } 82 | 83 | // is this a pruned node? if not, attempt to get some older blocks from it 84 | // look for service bits that don't include the NODE_NETWORK service flag 85 | if ($attributes[3] == 1032) { 86 | $prunedNodes++; 87 | continue; 88 | } 89 | 90 | $time = requestBlocks(); 91 | if ($time === false) { 92 | $blockDownloadFailed++; 93 | } else { 94 | $blockDownloadSucceeded++; 95 | $blockDownloadTimes[] = $time; 96 | } 97 | } 98 | 99 | $output = 100 | "Reachable nodes:$reachableNodes 101 | Unreachable nodes:$unreachableNodes 102 | Pruned nodes:$prunedNodes 103 | Block Download Failed:$blockDownloadFailed 104 | Block Download Succeeded:$blockDownloadSucceeded 105 | Block Download Times:" . implode(",", $blockDownloadTimes) . "\n"; 106 | file_put_contents("node_bandwidth_stats_" . $argv[1] . ".csv", $output); 107 | 108 | // ------------------ 109 | // P2P Message functions 110 | // ------------------ 111 | 112 | function fieldsize($field, $bytes = 1) { 113 | $length = $bytes * 2; 114 | $result = str_pad($field, $length, '0', STR_PAD_LEFT); 115 | return $result; 116 | } 117 | 118 | function swapEndian($hex) { 119 | return implode('', array_reverse(str_split($hex, 2))); 120 | } 121 | 122 | function byteSpaces($bytes) { // add spaces between bytes 123 | $bytes = implode(' ', str_split(strtoupper($bytes), 2)); 124 | return $bytes; 125 | } 126 | 127 | function timestamp($time) { // convert timestamp to network byte order 128 | $time = dechex($time); 129 | $time = fieldsize($time, 8); 130 | $time = swapEndian($time); 131 | return byteSpaces($time); 132 | } 133 | 134 | function networkaddress($ip, $port = '8333') { // convert ip address to network byte order 135 | $services = '01 00 00 00 00 00 00 00'; // 1 = NODE_NETWORK 136 | 137 | $ipv6_prefix = '00 00 00 00 00 00 00 00 00 00 FF FF'; 138 | 139 | $ip = explode('.', $ip); 140 | $ip = array_map("dechex", $ip); 141 | $ip = array_map("fieldsize", $ip); 142 | $ip = array_map("strtoupper", $ip); 143 | $ip = implode(' ', $ip); 144 | 145 | $port = dechex($port); // for some reason this is big-endian 146 | $port = byteSpaces($port); 147 | 148 | return "$services $ipv6_prefix $ip $port"; 149 | } 150 | 151 | function checksum($string) { 152 | $string = hex2bin($string); 153 | $hash = hash('sha256', hash('sha256', $string, true)); 154 | $checksum = substr($hash, 0, 8); 155 | return byteSpaces($checksum); 156 | } 157 | 158 | function makeMessage($command, $payload) { 159 | 160 | // Header 161 | $magicbytes = 'F9 BE B4 D9'; 162 | $commandHex = ""; 163 | for ($i = 0; $i < 12; $i++) { 164 | if (strlen($command) > $i) { 165 | $commandHex .= bin2hex($command[$i]) . " "; 166 | } else { 167 | $commandHex .= "00 "; 168 | } 169 | } 170 | $payload_size = bytespaces(swapEndian(fieldsize(dechex(strlen($payload) / 2), 4))); 171 | $checksum = checksum($payload); 172 | 173 | $header_array = [ 174 | 'magicbytes' => $magicbytes, 175 | 'command' => $commandHex, 176 | 'payload_size' => $payload_size, 177 | 'checksum' => $checksum, 178 | ]; 179 | 180 | $header = str_replace(' ', '', implode($header_array)); 181 | //echo 'Header: '; print_r($header_array); 182 | 183 | return $header.$payload; 184 | 185 | } 186 | 187 | function makeVersionPayload($version, $node_ip, $node_port, $local_ip, $local_port) { 188 | 189 | // settings 190 | $services = '01 00 00 00 00 00 00 00'; // (1 = NODE_NETORK) 191 | $user_agent = '00'; 192 | $start_height = 0; 193 | 194 | // prepare 195 | $version = bytespaces(swapEndian(fieldsize(dechex($version), 4))); 196 | $timestamp = timestamp(time()); // 73 43 c9 57 00 00 00 00 197 | $recv = networkaddress($node_ip, $node_port); 198 | $from = networkaddress($local_ip, $local_port); 199 | $nonce = bytespaces(swapEndian(fieldsize(dechex(mt_rand()), 8))); 200 | $start_height = bytespaces(swapEndian(fieldsize(dechex($start_height), 4))); 201 | 202 | $version_array = [ // hexadecimal, network byte order 203 | 'version' => $version, // 4 bytes (60002) 204 | 'services' => $services, // 8 bytes 205 | 'timestamp' => $timestamp, // 8 bytes 206 | 'addr_recv' => $recv, // 26 bytes 207 | 'addr_from' => $from, // 26 bytes 208 | 'nonce' => $nonce, // 8 bytes 209 | 'user_agent' => $user_agent, // varint 210 | 'start_height' => $start_height // 4 bytes 211 | ]; 212 | 213 | $version_payload = str_replace(' ', '', implode($version_array)); 214 | //echo 'Version Payload: '; print_r($version_array); 215 | 216 | return $version_payload; 217 | } 218 | 219 | 220 | function makeGetDataPayload() { 221 | 222 | $block_hashes = [ 223 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), // MSG_BLOCK inventory type 224 | swapEndian(strtoupper("00000000000000000024fb37364cbf81fd49cc2d51c09c75c35433c3a1945d04")), 225 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 226 | swapEndian(strtoupper("0000000000000000005c9959b3216f8640f94ec96edea69fe12ad7dee8b74e92")), 227 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 228 | swapEndian(strtoupper("000000000000000000877d93d1412ca671750152ba0862db95f073b82c04b191")), 229 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 230 | swapEndian(strtoupper("0000000000000000005467c7a728a3dcb17080d5fdca330043d51e298374f30e")), 231 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 232 | swapEndian(strtoupper("0000000000000000005d4da5924742e6d6372745f15c39feb05cf9b2e49e646d")), 233 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 234 | swapEndian(strtoupper("0000000000000000007150115460d0e92093aa937a913072d768f8136e289c2d")), 235 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 236 | swapEndian(strtoupper("000000000000000000063a1cc4280179e0f95d05c5d6edabcfe35ecbe29ab525")), 237 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 238 | swapEndian(strtoupper("0000000000000000002f6f0603757e974df0eb92db8e780d515b85d7de89bd98")), 239 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 240 | swapEndian(strtoupper("0000000000000000005f3b9fdd039ce2d228258cc822c04f1916b3162eded824")), 241 | bytespaces(swapEndian(fieldsize(dechex(2), 4))), 242 | swapEndian(strtoupper("0000000000000000006bcf0cd88715eeb3b399644cb50c087781c8236fa08929")) 243 | ]; 244 | 245 | $data_array = [ // hexadecimal, network byte order 246 | 'count' => bytespaces(swapEndian(fieldsize(dechex(10), 1))), 247 | 'inventory' => implode($block_hashes) 248 | ]; 249 | 250 | $data_payload = str_replace(' ', '', implode($data_array)); 251 | //echo 'GetData Payload: '; print_r($version_array); 252 | 253 | return $data_payload; 254 | } 255 | 256 | function connectPeer($peer_ip, $peer_port) { 257 | global $socket; 258 | $version = 70016; 259 | $local_ip = '127.0.0.1'; 260 | $local_port = 8333; 261 | 262 | // create Version Message (needs to be sent to node you want to connect to) 263 | $payload = makeVersionPayload($version, $peer_ip, $peer_port, $local_ip, $local_port); 264 | $message = makeMessage("version", $payload); 265 | $message_size = strlen($message) / 2; // the size of the message (in bytes) being sent 266 | 267 | // connect to socket and send version message 268 | $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 269 | $success = socket_connect($socket, $peer_ip, $peer_port); 270 | if (!$success) { 271 | return false; 272 | } 273 | 274 | $success = socket_send($socket, hex2bin($message), $message_size, 0); 275 | if (!$success) { 276 | return false; 277 | } 278 | 279 | sleep(1); 280 | $data = readSocketData(); 281 | 282 | if ($data === false || empty($data)) { 283 | return false; 284 | } 285 | 286 | //echo "\nReceived version response: "; print_r(bin2hex($data)); echo "\n"; 287 | 288 | // send verack response with empty payload so that we can send other messages next 289 | $message = makeMessage("verack", ""); 290 | $message_size = strlen($message) / 2; 291 | $success = socket_send($socket, hex2bin($message), $message_size, 0); 292 | 293 | if (!$success) { 294 | return false; 295 | } 296 | 297 | // listen for "ping" message (starts with 70 69 6e 67) 298 | $data = readSocketData(); 299 | 300 | if ($data === false || empty($data)) { 301 | return false; 302 | } 303 | 304 | //echo "\nPing data: " . bin2hex($data) . "\n"; 305 | 306 | // send "pong" reply with nonce we received 307 | //$message = makeMessage("pong", bin2hex($data)); 308 | //$message_size = strlen($message) / 2; 309 | //socket_send($socket, hex2bin($message), $message_size, 0); 310 | 311 | // listen for "getheaders" message 312 | $data = readSocketData(); 313 | 314 | //if ($data === false || empty($data)) { 315 | // return false; 316 | //} 317 | 318 | // send empty "headers" reply 319 | $message = makeMessage("headers", ""); 320 | $message_size = strlen($message) / 2; 321 | $success = socket_send($socket, hex2bin($message), $message_size, 0); 322 | 323 | if (!$success) { 324 | return false; 325 | } 326 | 327 | return true; 328 | } 329 | 330 | // request 10 full blocks from currently connected peer 331 | // return time in ms if we got all the expected data 332 | // return false if we failed to get all the data 333 | function requestBlocks() { 334 | global $socket; 335 | $payload = makeGetDataPayload(); 336 | $message = makeMessage("getdata", $payload); 337 | $message_size = strlen($message) / 2; 338 | //echo "Sent GetData message: $message\n\n"; 339 | $success = socket_send($socket, hex2bin($message), $message_size, 0); 340 | if (!$success) { 341 | return false; 342 | } 343 | 344 | $data = ""; 345 | // time how long it takes to receive blocks 346 | $start_time = round(microtime(true) * 1000); 347 | 348 | // 2 minute timeout if data stops flowing 349 | for ($i = 0; $i < 120; $i++) { 350 | $newData = readSocketData(); 351 | if (!empty($newData)) { 352 | $i = 0; 353 | $data .= $newData; 354 | } 355 | 356 | // we haven't received all the data yet, keep looping 357 | if (strlen($data) < 9770000) { 358 | sleep(1); 359 | } else { 360 | break; 361 | } 362 | } 363 | $end_time = round(microtime(true) * 1000); 364 | $total_time = $end_time - $start_time; 365 | //echo "Received getdata response: "; print_r(bin2hex($data)); echo "\n"; 366 | // data received should be > 9772653 bytes 367 | //echo "Received getdata response of length: " . strlen($data) . " in " . $total_time . "ms\n"; 368 | 369 | if (strlen($data) >= 9770000) { 370 | return $total_time; 371 | } else { 372 | return false; 373 | } 374 | } 375 | 376 | // keep reading data from socket until exhausted 377 | function readSocketData() { 378 | global $socket; 379 | $allData = $newData = ""; 380 | 381 | while (true) { 382 | // try 10 times over period of 0.1 second to read data 383 | for ($i = 0; $i < 10; $i++) { 384 | $success = socket_recv($socket, $newData, 1024, MSG_DONTWAIT); 385 | //$newData = socket_read($socket, 1); 386 | if (!empty($newData)) { 387 | $allData .= $newData; 388 | //echo bin2hex($newData); 389 | } else { // sleep for 1ms if we didn't read any data 390 | //echo " sleeping to read more data\n"; 391 | usleep(10000); 392 | } 393 | } 394 | 395 | // no more data available to read 396 | if (empty($newData)) { 397 | break; 398 | } 399 | //echo "Waiting to read more data...\n"; 400 | } 401 | 402 | return $allData; 403 | } -------------------------------------------------------------------------------- /countTransactionsManyInputs.php: -------------------------------------------------------------------------------- 1 | getBlockchaininfo()->get('blocks'); 11 | $heightRange = $maxBlockHeight - $height; 12 | $txByBlock = array(); 13 | $segwitTxByBlock = array(); 14 | 15 | // initialize start block vars 16 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 17 | $block = $bitcoind->getBlock($currentBlockHash, 2); 18 | $height++; 19 | 20 | while ($height < $maxBlockHeight) { 21 | $block = $bitcoind->getBlock($block->get('nextblockhash'), 2); 22 | $txByBlock[$height] = $segwitTxByBlock[$height] = 0; 23 | 24 | foreach ($block->get('tx') as $transaction) { 25 | if (count($transaction['vin']) > 50) { 26 | // if txid !== hash then it spends segwit inputs 27 | if ($transaction['txid'] != $transaction['hash']) { 28 | $segwitTxByBlock[$height]++; 29 | } else { 30 | $txByBlock[$height]++; 31 | } 32 | } 33 | } 34 | 35 | if ($height % 1000 == 0) { 36 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 37 | echo "$complete%\n"; 38 | } 39 | $height++; 40 | } 41 | 42 | ksort($txByBlock); 43 | ksort($segwitTxByBlock); 44 | $legacyTransactions = $segwitTransactions = 0; 45 | 46 | echo "Block Height,Legacy Transactions, Segwit Transactions:\n"; 47 | foreach ($txByBlock as $height => $count) { 48 | if ($height % 1000 != 0) { 49 | $legacyTransactions += $count; 50 | $segwitTransactions += $segwitTxByBlock[$height]; 51 | } else { 52 | echo "$height,$legacyTransactions,$segwitTransactions\n"; 53 | $legacyTransactions = $segwitTransactions = 0; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /dump_mempool_hex.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | for line in $(./bitcoin-cli getrawmempool); do 4 | hash=$(echo $line | tr -cd '[:alnum:]._-') 5 | echo $(./bitcoin-cli getrawtransaction $hash) 6 | done 7 | -------------------------------------------------------------------------------- /extractBitcoinNodeSyncTimes.php: -------------------------------------------------------------------------------- 1 | = 9 && !in_array("UpdateTip:", $data)) { 72 | continue; 73 | } 74 | 75 | 76 | // find the array value that includes the "height=" value; we only need to find and set this once since it's always the same 77 | if (!isset($heightField)) { 78 | foreach ($data as $index => $value) { 79 | if (strstr($value, "height")) { 80 | $heightField = $index; 81 | } 82 | } 83 | } 84 | 85 | if (strstr($data[$heightField],"=") == FALSE) { 86 | // block height is missing; ignore this line 87 | continue; 88 | } 89 | 90 | $height = explode("=", $data[$heightField])[1]; 91 | if ($height % 1000 != 0) { 92 | continue; 93 | } 94 | 95 | if ($height > $maxHeight) { 96 | break; 97 | } 98 | 99 | if ($version < 17) { 100 | $syncTime = floor((strtotime($data[0] . " " . $data[1]) - $startTime) / 60); 101 | } else { 102 | $syncTime = floor((strtotime($data[0]) - $startTime) / 60); 103 | } 104 | 105 | echo "$syncTime,$height\n"; 106 | } 107 | fclose($handle); 108 | } else { 109 | echo "ERROR: Failed to open log file\n"; 110 | } 111 | -------------------------------------------------------------------------------- /findBip39Words.php: -------------------------------------------------------------------------------- 1 | $one) { 49 | echo "$word\n"; 50 | } -------------------------------------------------------------------------------- /findDustSpendSpam.php: -------------------------------------------------------------------------------- 1 | getBlockchaininfo()->get('blocks'); 10 | $heightRange = $maxBlockHeight - $height; 11 | $spamBlockHeights = array(); 12 | $spamBlockValues = array(); 13 | $spamBlockFees = array(); 14 | $spamBlockSize = array(); 15 | 16 | // initialize start block vars 17 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 18 | $block = $bitcoind->getBlock($currentBlockHash, 2); 19 | $height++; 20 | 21 | function set_precision($value) { 22 | return sprintf('%.8F',$value); 23 | } 24 | 25 | while ($height < $maxBlockHeight) { 26 | $block = $bitcoind->getBlock($block->get('nextblockhash'), 2); 27 | 28 | foreach ($block->get('tx') as $transaction) { 29 | // Ignore transactions with over 1 output 30 | if (count($transaction['vout']) > 1) { 31 | continue; 32 | } 33 | 34 | // Look for large consolidations 35 | if (count($transaction['vin']) < 190) { 36 | continue; 37 | } 38 | 39 | // Ignore coinbase transactions 40 | if (isset($transaction['vin'][0]['coinbase'])) { 41 | continue; 42 | } 43 | 44 | // Search for outputs to a specific address 45 | //if (isset($transaction['vout'][0]['scriptPubKey']['addresses']) && $transaction['vout'][0]['scriptPubKey']['addresses'][0] != "1Enjoy1C4bYBr3tN4sMKxvvJDqG8NkdR4Z") { 46 | // continue; 47 | //} 48 | // Search for inputs from a specific address 49 | /* 50 | if (isset($transaction['vin'][0]['scriptSig']['asm'])) { 51 | if (explode(' ',$transaction['vin'][0]['scriptSig']['asm'])[1] != "045cce731a4d6308e5baf7d73ad2fcab298563bbc86404905d84e2b0ec314946a6d0e8076bd9db8e85ca0e7e5bd33f2adc629d48ac26f10e6ee459fc64efb5b8f5" && explode(' ',$transaction['vin'][0]['scriptSig']['asm'])[1] != "043e2baf0f082b5f7fa374051f09110bcf4d871e84c89904e30e85227d705952e9cafd536830a6126fa3a86af72ade7d1192e23a2aab3f64e67a6bd2046ca6f345") { 52 | continue; 53 | } 54 | }*/ 55 | 56 | // If we got this far, consider this transaction to be spam 57 | if (isset($spamBlockHeights[$height])) { 58 | $spamBlockHeights[$height]++; 59 | } else { 60 | $spamBlockHeights[$height] = 1; 61 | } 62 | 63 | if (isset($spamBlockSize[$height])) { 64 | $spamBlockSize[$height] += $transaction['vsize']; 65 | } else { 66 | $spamBlockSize[$height] = $transaction['vsize']; 67 | } 68 | 69 | // Calculate transaction fee paid (aggregate output value - aggregate input value) 70 | $inputValue = $outputValue = 0; 71 | foreach ($transaction['vin'] as $input) { 72 | $inputTx = $bitcoind->getRawtransaction($input['txid'], true)->get(); 73 | $inputValue += set_precision(floatval($inputTx['vout'][$input['vout']]['value'])); 74 | } 75 | foreach ($transaction['vout'] as $output) { 76 | $outputValue += set_precision(floatval($output['value'])); 77 | } 78 | $fee = $outputValue - $inputValue; 79 | if (isset($spamBlockFees[$height])) { 80 | $spamBlockFees[$height] += $fee; 81 | } else { 82 | $spamBlockFees[$height] = $fee; 83 | } 84 | 85 | if (isset($spamBlockValues[$height])) { 86 | $spamBlockValues[$height] += $outputValue; 87 | } else { 88 | $spamBlockValues[$height] = $outputValue; 89 | } 90 | } 91 | 92 | if ($height % 1000 == 0) { 93 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 94 | echo "$complete%\n"; 95 | } 96 | $height++; 97 | } 98 | 99 | // sort by block height ascending 100 | ksort($spamBlockHeights); 101 | 102 | echo "Block Height,Spam Txns:\n"; 103 | foreach ($spamBlockHeights as $height => $count) { 104 | echo "$height,$count\n"; 105 | } 106 | 107 | // sort by block height ascending 108 | ksort($spamBlockSize); 109 | 110 | echo "Block Height,Spam Txn Size:\n"; 111 | foreach ($spamBlockSize as $height => $size) { 112 | echo "$height,$size\n"; 113 | } 114 | 115 | // sort by block height ascending 116 | ksort($spamBlockFees); 117 | 118 | echo "Block Height,Spam Txn Fees:\n"; 119 | foreach ($spamBlockFees as $height => $fees) { 120 | echo "$height," . set_precision($fees) . "\n"; 121 | } 122 | 123 | // sort by block height ascending 124 | ksort($spamBlockValues); 125 | 126 | echo "Block Height,Spam Txn value:\n"; 127 | foreach ($spamBlockValues as $height => $value) { 128 | echo "$height,$value\n"; 129 | } 130 | -------------------------------------------------------------------------------- /findDustTransactionSpam.php: -------------------------------------------------------------------------------- 1 | getBlockchaininfo()->get('blocks'); 10 | $heightRange = $maxBlockHeight - $height; 11 | $spamBlockHeights = array(); 12 | $spamBlockValues = array(); 13 | $spamBlockFees = array(); 14 | $spamBlockSize = array(); 15 | 16 | // initialize start block vars 17 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 18 | $block = $bitcoind->getBlock($currentBlockHash, 2); 19 | $height++; 20 | 21 | function set_precision($value) { 22 | return sprintf('%.8F',$value); 23 | } 24 | 25 | while ($height < $maxBlockHeight) { 26 | $block = $bitcoind->getBlock($block->get('nextblockhash'), 2); 27 | 28 | foreach ($block->get('tx') as $transaction) { 29 | // Ignore transactions that don't have a lot of outputs 30 | if (count($transaction['vout']) < 50) { 31 | continue; 32 | } 33 | 34 | // Ignore likely coinjoins 35 | if (count($transaction['vin']) > 50) { 36 | continue; 37 | } 38 | 39 | // Ignore coinbase transactions 40 | if (isset($transaction['vin'][0]['coinbase'])) { 41 | continue; 42 | } 43 | 44 | // Search for outputs to a specific address 45 | //if (isset($transaction['vout'][0]['scriptPubKey']['addresses']) && $transaction['vout'][0]['scriptPubKey']['addresses'][0] != "1Enjoy1C4bYBr3tN4sMKxvvJDqG8NkdR4Z") { 46 | // continue; 47 | //} 48 | // Search for inputs from a specific address 49 | /* 50 | if (isset($transaction['vin'][0]['scriptSig']['asm'])) { 51 | if (explode(' ',$transaction['vin'][0]['scriptSig']['asm'])[1] != "045cce731a4d6308e5baf7d73ad2fcab298563bbc86404905d84e2b0ec314946a6d0e8076bd9db8e85ca0e7e5bd33f2adc629d48ac26f10e6ee459fc64efb5b8f5" && explode(' ',$transaction['vin'][0]['scriptSig']['asm'])[1] != "043e2baf0f082b5f7fa374051f09110bcf4d871e84c89904e30e85227d705952e9cafd536830a6126fa3a86af72ade7d1192e23a2aab3f64e67a6bd2046ca6f345") { 52 | continue; 53 | } 54 | }*/ 55 | 56 | // If a ton of the outputs have the same value, it's probably dust limit spam 57 | $values = array(); 58 | foreach ($transaction['vout'] as $output) { 59 | $formatted = set_precision(floatval($output['value'])); 60 | if (isset($values[$formatted])) { 61 | $values[$formatted]++; 62 | } else { 63 | $values[$formatted] = 1; 64 | } 65 | } 66 | 67 | // Determine if the transaction had dust outputs and, if so, log info 68 | foreach ($values as $value => $count) { 69 | if ($count < 50) { 70 | continue; 71 | } 72 | 73 | // search for a specific spam attack with this output value 74 | //if ($value != 0.00000001) { 75 | // continue; 76 | //} 77 | 78 | // If we got this far, consider this transaction to be spam 79 | if (isset($spamBlockHeights[$height])) { 80 | $spamBlockHeights[$height]++; 81 | } else { 82 | $spamBlockHeights[$height] = 1; 83 | } 84 | 85 | if (isset($spamBlockSize[$height])) { 86 | $spamBlockSize[$height] += $transaction['vsize']; 87 | } else { 88 | $spamBlockSize[$height] = $transaction['vsize']; 89 | } 90 | 91 | // Calculate transaction fee paid (aggregate output value - aggregate input value) 92 | $inputValue = $outputValue = 0; 93 | foreach ($transaction['vin'] as $input) { 94 | $inputTx = $bitcoind->getRawtransaction($input['txid'], true)->get(); 95 | $inputValue += set_precision(floatval($inputTx['vout'][$input['vout']]['value'])); 96 | } 97 | foreach ($transaction['vout'] as $output) { 98 | $outputValue += set_precision(floatval($output['value'])); 99 | } 100 | $fee = $outputValue - $inputValue; 101 | if (isset($spamBlockFees[$height])) { 102 | $spamBlockFees[$height] += $fee; 103 | } else { 104 | $spamBlockFees[$height] = $fee; 105 | } 106 | 107 | // Calculate total spammy output values 108 | foreach ($values as $v => $c) { 109 | if ($c < 50) { 110 | continue; 111 | } 112 | 113 | if ($v > 0.0001) { 114 | continue; 115 | } 116 | 117 | if (isset($spamBlockValues[$height])) { 118 | $spamBlockValues[$height] += $value * $count; 119 | } else { 120 | $spamBlockValues[$height] = $value * $count; 121 | } 122 | } 123 | 124 | // No need to keep iterating through output values 125 | break; 126 | } 127 | } 128 | 129 | if ($height % 1000 == 0) { 130 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 131 | echo "$complete%\n"; 132 | } 133 | $height++; 134 | } 135 | 136 | // sort by block height ascending 137 | ksort($spamBlockHeights); 138 | 139 | echo "Block Height,Spam Txns:\n"; 140 | foreach ($spamBlockHeights as $height => $count) { 141 | echo "$height,$count\n"; 142 | } 143 | 144 | // sort by block height ascending 145 | ksort($spamBlockSize); 146 | 147 | echo "Block Height,Spam Txn Size:\n"; 148 | foreach ($spamBlockSize as $height => $size) { 149 | echo "$height,$size\n"; 150 | } 151 | 152 | // sort by block height ascending 153 | ksort($spamBlockFees); 154 | 155 | echo "Block Height,Spam Txn Fees:\n"; 156 | foreach ($spamBlockFees as $height => $fees) { 157 | echo "$height," . set_precision($fees) . "\n"; 158 | } 159 | 160 | // sort by block height ascending 161 | ksort($spamBlockValues); 162 | 163 | echo "Block Height,Spam Txn value:\n"; 164 | foreach ($spamBlockValues as $height => $value) { 165 | echo "$height,$value\n"; 166 | } 167 | -------------------------------------------------------------------------------- /findEmptyBlocks.php: -------------------------------------------------------------------------------- 1 | 95% of the max weight, we assume the mempool was not empty 6 | 7 | require 'vendor/autoload.php'; 8 | 9 | use Denpa\Bitcoin\Client as BitcoinClient; 10 | 11 | $bitcoind = new BitcoinClient('http://user:password@localhost:8332/'); 12 | $startHeight = $height = 355000; // start height 13 | $maxBlockHeight = $bitcoind->getBlockchaininfo()->get('blocks'); 14 | $heightRange = $maxBlockHeight - $height; 15 | $emptyBlocks = array(); 16 | $monthCounts = array(); 17 | $secondsBetweenBlocks = array(); 18 | 19 | // initialize start block vars 20 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 21 | $block = $bitcoind->getBlockheader($currentBlockHash); 22 | $previousTimestamp = $block->get('time'); 23 | $nextBlockHash = $block->get('nextblockhash'); 24 | 25 | function getMiningPool($blockHeight) { 26 | $ch = curl_init(); 27 | curl_setopt($ch, CURLOPT_URL, "https://api.blockchair.com/bitcoin/dashboards/block/" . $blockHeight); 28 | curl_setopt($ch, CURLOPT_HEADER, 0); 29 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 30 | $result = curl_exec($ch); 31 | curl_close($ch); 32 | $json = json_decode($result); 33 | if (isset($json->data->$blockHeight->block->guessed_miner)) { 34 | return $json->data->$blockHeight->block->guessed_miner; 35 | } else { 36 | return "Unknown"; 37 | } 38 | } 39 | 40 | while ($height < $maxBlockHeight) { 41 | $block = $bitcoind->getBlockheader($nextBlockHash); 42 | $timestamp = $block->get('time'); 43 | $height = $block->get('height'); 44 | $transactionCount = $block->get('nTx'); 45 | 46 | if ($transactionCount == 1) { 47 | $secondsSinceLastBlock = $timestamp - $previousTimestamp; 48 | // If the weight of the previous and next blocks is near max weight, this block was not empty due to the mempool being empty 49 | $prevBlockWeight = $bitcoind->getBlock($bitcoind->getBlockhash($height - 1)->get())->get('weight'); 50 | $nextBlockWeight = $bitcoind->getBlock($block->get('nextblockhash'))->get('weight'); 51 | if ($prevBlockWeight > 3800000 && $nextBlockWeight > 3800000) { 52 | $date = gmdate("m-Y",$timestamp); 53 | $emptyBlocks[$height] = array($secondsSinceLastBlock, $date, getMiningPool($height)); 54 | if (key_exists($date, $monthCounts)) { 55 | $monthCounts[$date]++; 56 | } else { 57 | $monthCounts[$date] = 1; 58 | } 59 | } 60 | } 61 | 62 | 63 | if ($height % 1000 == 0) { 64 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 65 | echo "$complete%\n"; 66 | } 67 | 68 | $nextBlockHash = $block->get('nextblockhash'); 69 | $previousTimestamp = $timestamp; 70 | } 71 | 72 | // sort by height ascending 73 | ksort($emptyBlocks); 74 | 75 | echo "\nEmpty blocks\n"; 76 | foreach ($emptyBlocks as $emptyBlockHeight => $values) { 77 | echo "$emptyBlockHeight," . implode(",", $values) ."\n"; 78 | } 79 | 80 | echo "\nEmpty Blocks Per Month\n"; 81 | // sort by height ascending 82 | ksort($monthCounts); 83 | 84 | echo "\nEmpty blocks\n"; 85 | foreach ($monthCounts as $month => $count) { 86 | echo "$month,$count\n"; 87 | } 88 | -------------------------------------------------------------------------------- /findMissingBitcoinProjects.php: -------------------------------------------------------------------------------- 1 | message)) { 67 | echo $parts[3] . "/" . $parts[4] . " was " . $response->message . "\n"; 68 | continue; 69 | } 70 | $lastCommitDate = strtotime($response[0]->commit->author->date); 71 | $yearsAgo = strtotime('-2 year'); 72 | if ($lastCommitDate < $yearsAgo) { 73 | //echo $lastCommitDate . " is older than " . $yearsAgo . "\n"; 74 | } else { 75 | //echo $lastCommitDate . " is younger than " . $yearsAgo . "\n"; 76 | $activeRepos[] = $repo; 77 | } 78 | } 79 | 80 | // extract all href URLs from bitcoin & lightning resources HTML pages 81 | $localHTML = array('../lopp.net/lightning-information.html'); 82 | $files = scandir('../lopp.net/bitcoin-information/'); 83 | foreach ($files as $file) { 84 | if (str_ends_with($file, ".html")) { 85 | $localHTML[] = '../lopp.net/bitcoin-information/' . $file; 86 | } 87 | } 88 | 89 | foreach ($localHTML as $html) { 90 | $urlContent = file_get_contents($html); 91 | 92 | $dom = new DOMDocument(); 93 | @$dom->loadHTML($urlContent); 94 | $xpath = new DOMXPath($dom); 95 | $hrefs = $xpath->evaluate("/html/body//a"); 96 | 97 | for($i = 0; $i < $hrefs->length; $i++){ 98 | $href = $hrefs->item($i); 99 | $url = $href->getAttribute('href'); 100 | $url = filter_var($url, FILTER_SANITIZE_URL); 101 | // validate url 102 | if(!filter_var($url, FILTER_VALIDATE_URL) === false){ 103 | $resourceURLs[$url] = true; 104 | } 105 | } 106 | } 107 | 108 | // take the final repos that are left and figure out which ones aren't listed on lopp.net 109 | foreach ($activeRepos as $repo) { 110 | if (!array_key_exists($repo, $resourceURLs)) { 111 | echo $repo . "\n"; 112 | } 113 | } 114 | 115 | // used to find org name of a github URL 116 | function split2($string, $needle, $nth) { 117 | $max = strlen($string); 118 | $n = 0; 119 | for ($i=0; $i<$max; $i++) { 120 | if ($string[$i] == $needle) { 121 | $n++; 122 | if ($n >= $nth) { 123 | break; 124 | } 125 | } 126 | } 127 | $arr[] = substr($string, 0, $i); 128 | $arr[] = substr($string, $i+1, $max); 129 | 130 | return $arr; 131 | } -------------------------------------------------------------------------------- /findOpNopSpends.php: -------------------------------------------------------------------------------- 1 | getBlockhash($height)->get(); 20 | $block = $bitcoind->getBlock($currentBlockHash, 2); 21 | $height++; 22 | 23 | function set_precision($value) { 24 | return sprintf('%.8F',$value); 25 | } 26 | 27 | while ($height < $maxBlockHeight) { 28 | $block = $bitcoind->getBlock($block->get('nextblockhash'), 2); 29 | 30 | foreach ($block->get('tx') as $transaction) { 31 | // Ignore coinbase transactions 32 | if (isset($transaction['vin'][0]['coinbase'])) { 33 | continue; 34 | } 35 | 36 | // Search for outputs containing OP_NOPs in the scriptPubKey asm 37 | foreach ($transaction['vout'] as $output) { 38 | if (strpos($output['scriptPubKey']['asm'], "OP_NOP") !== FALSE || strpos($output['scriptPubKey']['asm'], "OP_CHECKLOCKTIMEVERIFY") !== FALSE || strpos($output['scriptPubKey']['asm'], "OP_CHECKSEQUENCEVERIFY") !== FALSE ) { 39 | echo "Block Height: $height, txid: " . $transaction['txid'] . "\n"; 40 | } 41 | } 42 | } 43 | 44 | if ($height % 1000 == 0) { 45 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 46 | echo "$complete%\n"; 47 | } 48 | $height++; 49 | } -------------------------------------------------------------------------------- /findTestnetDifficultyResetBlocks.php: -------------------------------------------------------------------------------- 1 | getBlock($nextBlockHash); 15 | $difficulty = $block->get('difficulty'); 16 | $time = $block->get('time'); 17 | 18 | // If this block was mined at a difficulty of 1 and over 20 minutes after the previous block, 19 | // it's safe to assume it was mined using the special testnet difficulty rule 20 | if ($difficulty == 1 && $time - $prevBlockTime >= 1200) { 21 | echo $height . "\n"; 22 | } 23 | 24 | $prevBlockTime = $time; 25 | $height++; 26 | $nextBlockHash = $block->get('nextblockhash'); 27 | } 28 | -------------------------------------------------------------------------------- /findTestnetRetargetBlocks.php: -------------------------------------------------------------------------------- 1 | getBlock($nextBlockHash); 14 | $difficulty = $block->get('difficulty'); 15 | 16 | // If this block was mined at a difficulty of 1 it's a difficulty retarget calculation height, 17 | // the difficulty will reset to 1 thanks to the special testnet difficulty rule 18 | if ($difficulty == 1 && $height % 2016 == 2015) { 19 | echo $height . "\n"; 20 | } 21 | 22 | $height++; 23 | $nextBlockHash = $block->get('nextblockhash'); 24 | } 25 | -------------------------------------------------------------------------------- /generateAllRepetitiveSeedPhrases.js: -------------------------------------------------------------------------------- 1 | // Import the bip39 package 2 | const bip39 = require('bip39'); 3 | 4 | // Get the BIP39 wordlist 5 | const wordlist = bip39.wordlists.english; 6 | 7 | // Function to repeat a word n times 8 | function repeatWord(word, times) { 9 | return Array(times).fill(word).join(' '); 10 | } 11 | 12 | // Iterate through each word in the wordlist 13 | wordlist.forEach(word => { 14 | let mnemonic = repeatWord(word, 12); 15 | 16 | if (bip39.validateMnemonic(mnemonic)) { 17 | console.log(mnemonic); 18 | } 19 | }); 20 | 21 | wordlist.forEach(word => { 22 | let mnemonic = repeatWord(word, 24); 23 | 24 | if (bip39.validateMnemonic(mnemonic)) { 25 | console.log(mnemonic); 26 | } 27 | }); -------------------------------------------------------------------------------- /generateDifficultyHistoryCSV.php: -------------------------------------------------------------------------------- 1 | difficulty != $currentDifficulty) { 31 | echo $block->height . "," . date("Y-m-d", $block->timestamp) . "," . $block->difficulty . "\n"; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /getAllCoinbaseInputBlockHeights.php: -------------------------------------------------------------------------------- 1 | vin as $input) { 30 | curl_setopt($ch, CURLOPT_URL, "https://blockstream.info/api/tx/" . $input->txid); 31 | $inputResult = curl_exec($ch); 32 | $inputTxJson = json_decode($inputResult); 33 | if ($inputTxJson->vin[0]->is_coinbase) { 34 | $blockHeights[$inputTxJson->status->block_height] = $inputTxJson->status->block_height; 35 | } else if ($recursive) { 36 | findCoinbaseInputs($inputTxJson, $recursive); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /getAllDepositsToAddress.php: -------------------------------------------------------------------------------- 1 | txid; 30 | // Skip known non-mining deposits 31 | if ($transaction->txid == "a800944d821e6fcc70925297e0ab8b0fa056b3870ff2ed8bf018a66dd3ad8559" 32 | || $transaction->txid == "7ac74d0e03cdcb8d71809a592212ba081416673041662bc538c49eb051e1d8a4" 33 | || $transaction->txid == "d4dfbda660da3a12086aa8f77b93f439ec6852bde4b8712a776cebf2eab2e2e8" 34 | || $transaction->txid == "0074f6ef948ef7d22421dd956c19ff4fcbe427de9ac3823af87264cd0bd5ca50" 35 | || $transaction->txid == "c7d2f831767b4b28151fc51bc636a51d7ba0accc063e598c9ac1f5942f2de17e" 36 | || $transaction->txid == "e7fcd68e4a014b354a737d24c23c1cfecdd458ac8d38918cf7b145f0a52ea4ee" 37 | || $transaction->txid == "5302a655ec11d0e47e020a8d02e417bac7eda2f349c458a12caa3a6bff59298c" 38 | || $transaction->txid == "b56447550f4df0fea169648c61bb3c2e3763c008883c7c47b036d647c886d360" 39 | || $transaction->txid == "3c4e1345f0cb5e6e73314b0c233db54b4397983956df89abf0429122d79ce4c7" 40 | || $transaction->txid == "8b0cf6bb862b60245030abf3ef35e9b38425b56f96a5f666f60ee4de0c7912a1" 41 | || $transaction->txid == "e9d2f91c6434366525d2211620f3c6064083b6f8f9ff6f6b81eff6d8598410fa" 42 | || $transaction->txid == "3dbba55165fa84dbdff834e42ffd795c516235ff1e5e942290d6af47d7020e0c" 43 | || $transaction->txid == "f45b0379c52a74dcdad8eefbceae5ec801fb2b268f0425ebf1fd03043ba2bdee") { 44 | continue; 45 | } 46 | 47 | // We only care about deposits; check the transaction outputs to see if one went to this address 48 | foreach ($transaction->vout as $output) { 49 | if ($output->scriptpubkey_address == $address) { 50 | $date = gmdate("m-d-Y", $transaction->status->block_time); 51 | echo $date . " " . $transaction->txid . " " . $output->value . "\n"; 52 | if (isset($deposits[$date])) { 53 | $deposits[$date] += $output->value; 54 | } else { 55 | $deposits[$date] = $output->value; 56 | } 57 | break; 58 | } 59 | } 60 | } 61 | } while (count($txList) == 25); // there are more pages of transactions to pull 62 | 63 | // Sort and print the results 64 | $total = 0; 65 | ksort($deposits); 66 | foreach ($deposits as $date => $amount) { 67 | $total += $amount; 68 | echo "$date,$amount\n"; 69 | } 70 | 71 | echo "\nTotal: $total\n"; -------------------------------------------------------------------------------- /getBitcoinPeerBandwidthStats.php: -------------------------------------------------------------------------------- 1 | results[0]->url; 14 | curl_setopt($ch, CURLOPT_URL, $snapshotURL); 15 | 16 | $result = curl_exec($ch); 17 | $snapshotJson = json_decode($result); 18 | 19 | $totalNodes = $attemptedNodes = 0; 20 | $networkBandwidth = array(); 21 | 22 | foreach ($snapshotJson->nodes as $nodeIP => $attributes) { 23 | $totalNodes++; 24 | } 25 | $percentOfNodes = floor($totalNodes / 100); 26 | 27 | foreach ($snapshotJson->nodes as $nodeIP => $attributes) { 28 | $attemptedNodes++; 29 | if ($attemptedNodes % $percentOfNodes == 0) { 30 | echo floor(($attemptedNodes / $totalNodes) * 100) . "% COMPLETE\n"; 31 | } 32 | 33 | // 11 is ASN 34 | if ($attributes[11] == 'TOR') { 35 | continue; 36 | } 37 | 38 | // if node IP address includes bracket charts, it's IPV6 39 | if (strstr($nodeIP, '[') !== false) { 40 | continue; 41 | } 42 | 43 | // this is an IPV4 peer; scrape its individual stats page 44 | curl_setopt($ch, CURLOPT_URL, "https://bitnodes.io/api/v1/nodes/" . explode(":", $nodeIP)[0] . "-" . explode(":", $nodeIP)[1] . "/"); 45 | 46 | $result = curl_exec($ch); 47 | $nodeJson = json_decode($result); 48 | //echo $nodeJson->mbps . "\n"; 49 | 50 | // throw away invalid values 51 | if (empty($nodeJson->mbps) || !isset($nodeJson->mbps) || !is_numeric($nodeJson->mbps)) { 52 | continue; 53 | } 54 | 55 | // bucket by network 56 | if (array_key_exists($nodeJson->data[12], $networkBandwidth)) { 57 | $networkBandwidth[$nodeJson->data[12]][] = $nodeJson->mbps; 58 | } else { 59 | $networkBandwidth[$nodeJson->data[12]] = array($nodeJson->mbps); 60 | } 61 | } 62 | 63 | echo "\n\n"; 64 | 65 | // Print average bandwidth by network 66 | foreach ($networkBandwidth as $network => $speeds) { 67 | $averageSpeed = array_sum($speeds)/count($speeds); 68 | echo $network . "," . $averageSpeed . "\n"; 69 | } -------------------------------------------------------------------------------- /getBlockTimeDistribution.php: -------------------------------------------------------------------------------- 1 | getBlockChaininfo()->get('blocks'); 10 | $heightRange = $maxBlockHeight - $height; 11 | $slowBlocks = array(); 12 | $secondsBetweenBlocks = array(); 13 | $negativeBlockHeights = array(); 14 | 15 | // initialize start block vars 16 | //print_r($bitcoind->getBlockHash($height));exit; 17 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 18 | $block = $bitcoind->getBlockheader($currentBlockHash); 19 | $previousTimestamp = $block->get('time'); 20 | $nextBlockHash = $block->get('nextblockhash'); 21 | 22 | while ($height < $maxBlockHeight) { 23 | $block = $bitcoind->getBlockheader($nextBlockHash); 24 | $timestamp = $block->get('time'); 25 | $secondsSinceLastBlock = $timestamp - $previousTimestamp; 26 | 27 | if (key_exists($secondsSinceLastBlock, $secondsBetweenBlocks)) { 28 | $secondsBetweenBlocks[$secondsSinceLastBlock]++; 29 | } else { 30 | $secondsBetweenBlocks[$secondsSinceLastBlock] = 1; 31 | } 32 | 33 | // make a note of this anomaly 34 | if ($secondsSinceLastBlock > 10000) { 35 | $slowBlocks[$height] = $secondsSinceLastBlock; 36 | } 37 | 38 | // make a note of this anomaly 39 | if ($secondsSinceLastBlock < 0) { 40 | $negativeBlockHeights[$height] = $secondsSinceLastBlock; 41 | } 42 | 43 | if ($height % 1000 == 0) { 44 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 45 | echo "$complete%\n"; 46 | } 47 | 48 | $height++; 49 | $nextBlockHash = $block->get('nextblockhash'); 50 | $previousTimestamp = $timestamp; 51 | } 52 | 53 | // sort by seconds ascending 54 | ksort($secondsBetweenBlocks); 55 | // sort by block height ascending 56 | ksort($negativeBlockHeights); 57 | 58 | $negativeTimeDeltaCount = 0; 59 | foreach ($secondsBetweenBlocks as $seconds => $count) { 60 | if ($secondsBetweenBlocks < 0) { 61 | $negativeTimeDeltaCount++; 62 | } 63 | echo "$seconds,$count\n"; 64 | } 65 | 66 | echo "\nExtremely slow blocks\n"; 67 | echo "Block Height,Seconds Delta:\n"; 68 | foreach ($slowBlocks as $height => $seconds) { 69 | echo "$height,$seconds\n"; 70 | } 71 | 72 | echo "\nNegative time delta blocks\n"; 73 | echo "Block Height,Seconds Delta:\n"; 74 | foreach ($negativeBlockHeights as $height => $seconds) { 75 | echo "$height,$seconds\n"; 76 | } 77 | 78 | echo "\nThere were $negativeTimeDeltaCount negative delta blocks\n"; -------------------------------------------------------------------------------- /getFirstDepositToAddress.php: -------------------------------------------------------------------------------- 1 | txid; 30 | 31 | // We only care about deposits; check the transaction outputs to see if one went to this address 32 | foreach ($transaction->vout as $output) { 33 | if (isset($output->scriptpubkey_address) && $output->scriptpubkey_address == $address) { 34 | $oldestDepositTxId = $lastTxID; 35 | } 36 | } 37 | } 38 | } while (count($txList) == 25); // there are more pages of transactions to pull 39 | 40 | echo "\nFirst deposit transaction: $oldestDepositTxId\n"; -------------------------------------------------------------------------------- /getHistoricalHashrateEstimates.php: -------------------------------------------------------------------------------- 1 | getNetworkHashPS($target, $height)->get(); 29 | // store hashrate in exahashes with 2 decimals precison 30 | $estimates[$height][$target] = number_format($hashrate / 1E+18, 2); 31 | } 32 | 33 | if ($height % 1000 == 0) { 34 | $complete = round(100*(($height - $startHeight) / $heightRange),2); 35 | echo "$complete%\n"; 36 | } 37 | 38 | $height++; 39 | } 40 | 41 | // sort by height ascending 42 | ksort($estimates); 43 | 44 | echo "\nBlock Height|1|2|3|4|5|6|7|8|9|10|20|30|40|50|60|70|80|90|100|200|300|400|500|600|700|800|900|1000|2000|3000|4000|5000|6000|7000|8000|9000|10000\n"; 45 | foreach ($estimates as $estimateHeight => $results) { 46 | echo $estimateHeight; 47 | foreach ($results as $target => $hashrate) { 48 | echo "|$hashrate"; 49 | } 50 | echo "\n"; 51 | } -------------------------------------------------------------------------------- /getOFACBitcoinAddresses.php: -------------------------------------------------------------------------------- 1 | ; 21 | preg_match_all('/XBT \w+/', $result, $matches); 22 | 23 | foreach ($matches[0] as $match) { 24 | $addresses[] = substr($match, 4, -1); 25 | } 26 | 27 | // Sort and print the results 28 | sort($addresses); 29 | foreach ($addresses as $address) { 30 | echo $address . "\n"; 31 | } -------------------------------------------------------------------------------- /goldiblocks/blockWeightHistory.csv: -------------------------------------------------------------------------------- 1 | height,weight,sats / WU 2 | 770000,2822593424,3 3 | 771000,3364026657,3 4 | 772000,3125489018,3 5 | 773000,2880719313,3 6 | 774000,3397660988,4 7 | 775000,3863075384,4 8 | 776000,3977840568,4 9 | 777000,3970881270,3 10 | 778000,3893962697,4 11 | 779000,3953918589,4 12 | 780000,3985661827,6 13 | 781000,3981819787,6 14 | 782000,3981783219,5 15 | 783000,3985759975,5 16 | 784000,3985745295,5 17 | 785000,3985773332,4 18 | 786000,3890381017,4 19 | 787000,3993727417,10 20 | 788000,3973675581,52 21 | 789000,3969735377,26 22 | 790000,3985622018,16 23 | 791000,3989763793,12 24 | 792000,3985746332,11 25 | 793000,3989687486,11 26 | 794000,3977753087,7 27 | 795000,3981656215,7 28 | 796000,3985746143,5 29 | 797000,3985842520,3 30 | 798000,3985792600,3 31 | 799000,3985778448,4 32 | 800000,3981790522,3 33 | 801000,3985822187,3 34 | 802000,3985774560,3 35 | 803000,3989727839,2 36 | 804000,3985937959,3 37 | 805000,3989764555,3 38 | 806000,3981794711,5 39 | 807000,3985744641,5 40 | 808000,3989801587,7 41 | 809000,3989741613,5 42 | 810000,3985808021,4 43 | 811000,3981346027,3 44 | 812000,3988964511,2 45 | 813000,3988542023,4 46 | 814000,3981787121,3 47 | 815000,3993735413,14 48 | 816000,3973826474,24 49 | 817000,3977749743,36 50 | 818000,3973704190,18 51 | 819000,3969669295,23 52 | 820000,3973787294,26 53 | 821000,3961801910,70 54 | 822000,3973807003,45 55 | 823000,3981716492,43 56 | 824000,3991707990,20 57 | 825000,3973803400,21 58 | 826000,3985830696,16 59 | 827000,3975403351,9 60 | 828000,3977637286,13 61 | 829000,3985695690,8 62 | 830000,3989802935,7 63 | 831000,3989744115,5 64 | 832000,3977786082,8 65 | 833000,3989704202,10 66 | 834000,3973840687,6 67 | 835000,3981829965,6 68 | 836000,3989795665,4 69 | 837000,3985923237,4 70 | 838000,3981841686,12 71 | 839000,3978021945,19 72 | 840000,3989841864,67 73 | 841000,3973868934,8 74 | 842000,3977746257,8 75 | 843000,3969701821,4 76 | 844000,3961804753,3 77 | 845000,3961804771,5 78 | 846000,3969876031,16 79 | 847000,3941915811,11 80 | 848000,3981866271,5 81 | 849000,3989785091,3 82 | 850000,3985745559,2 83 | 851000,3993719057,2 84 | 852000,3985806601,2 85 | 853000,3981663311,1 86 | 854000,3993682579,1 87 | 855000,3967291510,1 88 | 856000,3985801610,1 89 | 857000,3981742741,3 90 | 858000,3993691405,1 91 | 859000,3977710566,1 92 | 860000,3977690616,1 93 | 861000,3981743745,1 94 | 862000,3989788854,1 95 | 863000,3973887540,1 96 | 864000,3989811286,1 97 | 865000,3989796867,6 98 | 866000,3973763296,3 99 | 867000,3969808399,3 100 | 868000,3957937885,2 101 | 869000,3989838303,1 102 | 870000,3989848459,3 103 | 871000,3981867488,2 104 | 872000,3989969200,2 105 | 873000,3981993913,2 106 | 874000,3989906621,2 107 | 875000,3977875104,2 108 | 876000,3989834807,1 109 | 877000,3989867666,1 110 | 878000,3965064428,1 111 | 879000,3977110937,1 112 | 880000,3984127400,1 113 | 881000,3866129747,1 114 | 882000,3945375116,1 115 | 883000,3860714509,1 116 | 884000,3893513529,1 117 | 885000,3993909494,1 118 | 886000,3981843718,1 119 | 887000,3981886684,1 120 | 888000,3984837003,1 121 | 889000,3981922468,1, -------------------------------------------------------------------------------- /goldiblocks/blockWeightvsFees.php: -------------------------------------------------------------------------------- 1 | = 64) { 23 | return 0.0; 24 | } 25 | 26 | return $initialReward / pow(2, $halvings); 27 | } 28 | 29 | // initialize start block vars 30 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 31 | $block = $bitcoind->getBlockheader($currentBlockHash); 32 | $nextBlockHash = $block->get('nextblockhash'); 33 | 34 | while ($height < $maxBlockHeight) { 35 | $block = $bitcoind->getBlock($nextBlockHash); 36 | $weight = $block["weight"]; 37 | $coinbase = $bitcoind->getRawtransaction($block["tx"][0], true)->get(); 38 | 39 | $fees = 0; 40 | foreach ($coinbase['vout'] as $output) { 41 | $fees += $output['value']; 42 | } 43 | 44 | $fees -= getSubsidy($height); 45 | $fees *= 100_000_000; 46 | 47 | $stats[$height] = array("fees" => $fees, "weight" => $weight); 48 | $height++; 49 | $nextBlockHash = $block->get('nextblockhash'); 50 | } 51 | 52 | // aggregate stats into 1,000 block periods 53 | for ($periodStartHeight = $startHeight; $periodStartHeight < $maxBlockHeight; $periodStartHeight += 1000) { 54 | $totalWeight = 0; 55 | $totalFees = 0; 56 | 57 | for ($height = $periodStartHeight; $height < $periodStartHeight + 1000; $height++) { 58 | $totalWeight += $stats[$height]["weight"]; 59 | $totalFees += $stats[$height]["fees"]; 60 | } 61 | 62 | $feePerWU = round($totalFees / $totalWeight); 63 | echo "$periodStartHeight,$totalWeight,$totalFees,$feePerWU\n"; 64 | } -------------------------------------------------------------------------------- /goldiblocks/goldiblocksAlgorithm.php: -------------------------------------------------------------------------------- 1 | $data[0], 22 | "weight" => $data[1], 23 | "feerate" => $data[2] 24 | ); 25 | } 26 | fclose($handle); 27 | } else { 28 | echo "ERROR: Failed to open CSV file\n"; 29 | } 30 | 31 | $currentDynamicSize = 4_000_000; 32 | 33 | foreach ($weights as $index => $weight) { 34 | $averageWeight = round($weight["weight"] / 1000); 35 | if ($averageWeight < $currentDynamicSize * 0.95) { 36 | $feerateDelta = $averageWeight / $currentDynamicSize; 37 | } else if ($weight["feerate"] <= 10) { 38 | $feerateDelta = 0.95; 39 | // determine relative delta between previous epoch's sats/WU and current epoch 40 | } else if ($weights[$index - 1]["feerate"] < 10) { 41 | $feerateDelta = sqrt(($weight["feerate"] - 10) / 10); 42 | } else if ($weight["feerate"] > $weights[$index - 1]["feerate"]) { // fee rate increased 43 | $feerateDelta = 1 + sqrt(abs(($weight["feerate"] - $weights[$index - 1]["feerate"]) / $weights[$index - 1]["feerate"])); 44 | } else { // fee rate decreased 45 | $feerateDelta = 1 - sqrt(abs(($weight["feerate"] - $weights[$index - 1]["feerate"]) / $weights[$index - 1]["feerate"])); 46 | } 47 | 48 | // set safety boundaries 49 | // delta must be >= 0.5 and <= 2 50 | if ($feerateDelta < 0.5) { 51 | $feerateDelta = 0.5; 52 | } else if ($feerateDelta > 2) { 53 | $feerateDelta = 2; 54 | } 55 | 56 | $currentDynamicSize = round($currentDynamicSize * $feerateDelta); 57 | if ($currentDynamicSize < 400_000) { 58 | $currentDynamicSize = 400_000; 59 | } 60 | echo $weight["height"] . ',' . $currentDynamicSize . "\n"; 61 | } -------------------------------------------------------------------------------- /lnd-channel-backup-dropbox.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script listens for changes to lnd's channel backup file 3 | # and when changes are detected, uploads the timestamped file to dropbox 4 | # Forked from https://gist.github.com/vindard/e0cd3d41bb403a823f3b5002488e3f90 5 | # See above link for dropbox API setup guide and systemd setup guide 6 | 7 | # SET DROPBOX API KEY FOR UPLOADS 8 | DROPBOX_APITOKEN="ADD_OAUTH_LONG_LIVED_TOKEN_WITH_WRITE_ACCESS_HERE" 9 | 10 | # OPTIONAL SET A DEVICE NAME TO BE USED FOR BACKUPS (DEFAULTS TO /etc/hostname) 11 | DEVICE="" 12 | 13 | # INOTIFY CHECK 14 | # -------------- 15 | 16 | install_inotify () { 17 | sudo apt update 18 | sudo apt install -y inotify-tools 19 | } 20 | 21 | inotifycheck () { 22 | dpkg -s "inotify-tools" &> /dev/null 23 | if [ ! $? -eq 0 ]; then 24 | install_inotify 25 | fi 26 | } 27 | 28 | 29 | install_jq () { 30 | sudo apt update 31 | sudo apt install -y jq 32 | } 33 | 34 | jqcheck () { 35 | dpkg -s "jq" &> /dev/null 36 | if [ ! $? -eq 0 ]; then 37 | install_jq 38 | fi 39 | } 40 | 41 | # SETUP 42 | # -------------- 43 | 44 | setup_files_and_folders () { 45 | # Fetches the user whose home folder the directories will be stored under 46 | ADMINUSER=( $(ls /home | grep -v bitcoin) ) 47 | 48 | if [ -z "$DEVICE" ] ; then 49 | DEVICE=$(echo $(cat /etc/hostname)) 50 | fi 51 | DEVICE=$(echo $DEVICE | awk '{print tolower($0)}' | sed -e 's/ /-/g') 52 | 53 | # Setup folders and filenames 54 | DATADIR=/home/$ADMINUSER/.lnd 55 | WORKINGDIR=/home/$ADMINUSER/.lnd/channel-backups 56 | BACKUPFOLDER=$DEVICE 57 | 58 | # channel.backup file details 59 | CHANFILEDIR=data/chain/bitcoin/mainnet 60 | BACKUPFILE=channel.backup 61 | SOURCEFILE=$DATADIR/$CHANFILEDIR/$BACKUPFILE 62 | 63 | # Make sure necessary folders exist 64 | if [[ ! -e ${WORKINGDIR} ]]; then 65 | mkdir -p ${WORKINGDIR} 66 | fi 67 | cd ${WORKINGDIR} 68 | 69 | if [[ ! -e ${BACKUPFOLDER} ]]; then 70 | mkdir -p ${BACKUPFOLDER} 71 | fi 72 | cd ${BACKUPFOLDER} 73 | } 74 | 75 | 76 | # CHECKS 77 | # -------------- 78 | 79 | online_check () { 80 | wget -q --tries=10 --timeout=20 --spider http://google.com 81 | if [[ $? -eq 0 ]]; then 82 | ONLINE=true 83 | else 84 | ONLINE=false 85 | fi 86 | #echo "Online: "$ONLINE 87 | } 88 | 89 | dropbox_api_check () { 90 | VALID_DROPBOX_APITOKEN=false 91 | curl -s -X POST https://api.dropboxapi.com/2/users/get_current_account \ 92 | --header "Authorization: Bearer "$DROPBOX_APITOKEN | grep rror 93 | if [[ ! $? -eq 0 ]] ; then 94 | VALID_DROPBOX_APITOKEN=true 95 | else 96 | echo "Invalid Dropbox API Token!" 97 | fi 98 | } 99 | 100 | dropbox_upload_check () { 101 | UPLOAD_TO_DROPBOX=false 102 | if [ ! -z $DROPBOX_APITOKEN ] ; then 103 | online_check 104 | if [ $ONLINE = true ] ; then 105 | dropbox_api_check 106 | else 107 | echo "Please check that the internet is connected and try again." 108 | fi 109 | 110 | if [ $VALID_DROPBOX_APITOKEN = true ] ; then 111 | UPLOAD_TO_DROPBOX=true 112 | fi 113 | fi 114 | } 115 | 116 | 117 | # UPLOAD 118 | # -------------- 119 | 120 | upload_to_dropbox () { 121 | FINISH=$(curl -s -X POST https://content.dropboxapi.com/2/files/upload \ 122 | --header "Authorization: Bearer "${DROPBOX_APITOKEN}"" \ 123 | --header "Dropbox-API-Arg: {\"path\": \"/"$BACKUPFOLDER"/"$1"\",\"mode\": \"overwrite\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}" \ 124 | --header "Content-Type: application/octet-stream" \ 125 | --data-binary @$1) 126 | #echo $FINISH 127 | UPLOADTIME=$(echo $FINISH | jq -r .server_modified) 128 | if [ ! -z $UPLOADTIME ] ; then 129 | echo "Successfully uploaded!" 130 | else 131 | echo "Unknown error when uploading..." 132 | fi 133 | } 134 | 135 | # RUN CHECKS AND IF PASS, EXECUTE BACKUP TO DROPBOX 136 | run_dropbox_backup () { 137 | dropbox_upload_check 138 | if [ $UPLOAD_TO_DROPBOX = true ] ; then 139 | upload_to_dropbox $1 140 | fi 141 | } 142 | 143 | 144 | ############## 145 | # RUN SCRIPT 146 | ############## 147 | 148 | run_backup_on_change () { 149 | echo "Copying backup file..." 150 | BACKUPFILE_TIMESTAMPED=$BACKUPFILE-$(date +%s) 151 | cp $SOURCEFILE $BACKUPFILE_TIMESTAMPED 152 | md5sum $SOURCEFILE > $BACKUPFILE_TIMESTAMPED.md5 153 | sed -i 's/\/.*\///g' $BACKUPFILE_TIMESTAMPED.md5 154 | 155 | echo 156 | echo "Uploading backup file: '"${BACKUPFILE_TIMESTAMPED}"'..." 157 | run_dropbox_backup $BACKUPFILE_TIMESTAMPED 158 | echo "---" 159 | echo "Uploading signature: '"${BACKUPFILE_TIMESTAMPED}.md5"'..." 160 | run_dropbox_backup $BACKUPFILE_TIMESTAMPED.md5 161 | } 162 | 163 | run () { 164 | inotifycheck 165 | jqcheck 166 | setup_files_and_folders 167 | run_backup_on_change 168 | while true; do 169 | inotifywait $SOURCEFILE 170 | run_backup_on_change 171 | echo 172 | done 173 | } 174 | 175 | run 176 | 177 | -------------------------------------------------------------------------------- /node_connection_manager/README.md: -------------------------------------------------------------------------------- 1 | Bitcoin Node Connection Manager 2 | =============== 3 | 4 | This PHP script uses bitcoind's RPC API to rebalance the connections between a set of nodes you operate. 5 | The goal is to minimize redundant peer node connections amongst your pool to maximize the number of uniquely connected peers. 6 | 7 | Getting Started 8 | --------------- 9 | 1. Add the IP Addresses and corresponding RPC usernames / passwords to the $nodes array in node_rebalance.php: 10 | 11 | `$nodes = array(array('ip' => '127.0.0.1', 'port' => '8332', 'username' => 'rpcuser', 'password' => 'rpcpw'));` 12 | 2. Perform a test run of the rebalance script via the command line and check output for errors / success: 13 | 14 | `php node_rebalance.php` 15 | 16 | 3. Automate rebalancing by adding cron entry to call script. For example, in /etc/crontab: 17 | 18 | `/30 * * * * root /path/to/node_rebalance.php > /dev/null` 19 | -------------------------------------------------------------------------------- /node_connection_manager/bitcoin_client.php: -------------------------------------------------------------------------------- 1 | setSSL('/full/path/to/mycertificate.cert'); 47 | 48 | // Make calls to bitcoind as methods for your object. Responses are returned as an array. 49 | // Examples: 50 | $bitcoin->getinfo(); 51 | $bitcoin->getrawtransaction('0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098',1); 52 | $bitcoin->getblock('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'); 53 | 54 | // The full response (not usually needed) is stored in $this->response while the raw JSON is stored in $this->raw_response 55 | 56 | // When a call fails for any reason, it will return FALSE and put the error message in $this->error 57 | // Example: 58 | echo $bitcoin->error; 59 | 60 | // The HTTP status code can be found in $this->status and will either be a valid HTTP status code or will be 0 if cURL was unable to connect. 61 | // Example: 62 | echo $bitcoin->status; 63 | 64 | */ 65 | 66 | class Bitcoin { 67 | // Configuration options 68 | private $username; 69 | private $password; 70 | private $proto; 71 | private $host; 72 | private $port; 73 | private $url; 74 | private $CACertificate; 75 | 76 | // Information and debugging 77 | public $status; 78 | public $error; 79 | public $raw_response; 80 | public $response; 81 | 82 | private $id = 0; 83 | 84 | /** 85 | * @param string $username 86 | * @param string $password 87 | * @param string $host 88 | * @param int $port 89 | * @param string $proto 90 | * @param string $url 91 | */ 92 | function __construct($username, $password, $host = 'localhost', $port = 8332, $url = null) { 93 | $this->username = $username; 94 | $this->password = $password; 95 | $this->host = $host; 96 | $this->port = $port; 97 | $this->url = $url; 98 | 99 | // Set some defaults 100 | $this->proto = 'http'; 101 | $this->CACertificate = null; 102 | } 103 | 104 | /** 105 | * @param string|null $certificate 106 | */ 107 | function setSSL($certificate = null) { 108 | $this->proto = 'https'; // force HTTPS 109 | $this->CACertificate = $certificate; 110 | } 111 | 112 | function __call($method, $params) { 113 | $this->status = null; 114 | $this->error = null; 115 | $this->raw_response = null; 116 | $this->response = null; 117 | 118 | // If no parameters are passed, this will be an empty array 119 | $params = array_values($params); 120 | 121 | // The ID should be unique for each call 122 | $this->id++; 123 | 124 | // Build the request, it's ok that params might have any empty array 125 | $request = json_encode(array( 126 | 'method' => $method, 127 | 'params' => $params, 128 | 'id' => $this->id 129 | )); 130 | 131 | // Build the cURL session 132 | $curl = curl_init("{$this->proto}://{$this->username}:{$this->password}@{$this->host}:{$this->port}/{$this->url}"); 133 | $options = array( 134 | CURLOPT_RETURNTRANSFER => TRUE, 135 | CURLOPT_FOLLOWLOCATION => TRUE, 136 | CURLOPT_MAXREDIRS => 10, 137 | CURLOPT_HTTPHEADER => array('Content-type: application/json'), 138 | CURLOPT_POST => TRUE, 139 | CURLOPT_POSTFIELDS => $request 140 | ); 141 | 142 | if ($this->proto == 'https') { 143 | // If the CA Certificate was specified we change CURL to look for it 144 | if ($this->CACertificate != null) { 145 | $options[CURLOPT_CAINFO] = $this->CACertificate; 146 | $options[CURLOPT_CAPATH] = DIRNAME($this->CACertificate); 147 | } 148 | else { 149 | // If not we need to assume the SSL cannot be verified so we set this flag to FALSE to allow the connection 150 | $options[CURLOPT_SSL_VERIFYPEER] = FALSE; 151 | } 152 | } 153 | 154 | curl_setopt_array($curl, $options); 155 | 156 | // Execute the request and decode to an array 157 | $this->raw_response = curl_exec($curl); 158 | $this->response = json_decode($this->raw_response, TRUE); 159 | 160 | // If the status is not 200, something is wrong 161 | $this->status = curl_getinfo($curl, CURLINFO_HTTP_CODE); 162 | 163 | // If there was no error, this will be an empty string 164 | $curl_error = curl_error($curl); 165 | 166 | curl_close($curl); 167 | 168 | if (!empty($curl_error)) { 169 | $this->error = $curl_error; 170 | } 171 | 172 | if ($this->response['error']) { 173 | // If bitcoind returned an error, put that in $this->error 174 | $this->error = $this->response['error']['message']; 175 | } 176 | elseif ($this->status != 200) { 177 | // If bitcoind didn't return a nice error message, we need to make our own 178 | switch ($this->status) { 179 | case 400: 180 | $this->error = 'HTTP_BAD_REQUEST'; 181 | break; 182 | case 401: 183 | $this->error = 'HTTP_UNAUTHORIZED'; 184 | break; 185 | case 403: 186 | $this->error = 'HTTP_FORBIDDEN'; 187 | break; 188 | case 404: 189 | $this->error = 'HTTP_NOT_FOUND'; 190 | break; 191 | } 192 | } 193 | 194 | if ($this->error) { 195 | return FALSE; 196 | } 197 | 198 | return $this->response['result']; 199 | } 200 | 201 | function getHost() { 202 | return $this->host; 203 | } 204 | 205 | function getPort() { 206 | return $this->port; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /node_connection_manager/node_rebalance.php: -------------------------------------------------------------------------------- 1 | '127.0.0.1', 11 | 'port' => '8332', 12 | 'username' => 'RPCUserHere', 13 | 'password' => 'passwordHere' 14 | ), 15 | array( 16 | 'ip' => '192.168.0.1', 17 | 'port' => '8332', 18 | 'username' => 'RPCUserHere', 19 | 'password' => 'passwordHere' 20 | ), 21 | ); 22 | 23 | // don't allow multiple instances of this script to run simultaneously 24 | const PID_FILE = '/tmp/nodemanager.pid'; 25 | 26 | if (file_exists(PID_FILE)) { 27 | $pid = file_get_contents(PID_FILE); 28 | if (file_exists("/proc/$pid")) { 29 | error_log('An instance of the node manager script is already running.'); 30 | exit(1); 31 | } else { 32 | error_log('Previous process exited without cleaning pidfile.'); 33 | unlink(PID_FILE); 34 | } 35 | } 36 | $h = fopen(PID_FILE, 'w'); 37 | if ($h) { 38 | fwrite($h, getmypid()); 39 | } 40 | fclose($h); 41 | 42 | // build node IP whitelist from our pool of nodes 43 | $nodes = array(); 44 | $whitelist = array(); 45 | foreach ($config as $index => $node) { 46 | $nodes[] = new Bitcoin($node['username'], $node['password'], $node['ip'], $node['port']); 47 | //$nodes[$index]->setSSL($certificate); optionally enable SSL here 48 | $whitelist[$node['ip'] . ':8333'] = TRUE; 49 | } 50 | 51 | // query each node to check that it's online 52 | foreach ($nodes as $index => $node) { 53 | if (FALSE === $node->getinfo()) { 54 | // node is offline; remove from list of nodes 55 | unset($nodes[$index]); 56 | } 57 | } 58 | 59 | // query each node for all of its peers 60 | $connectedPeers = array(); 61 | foreach ($nodes as $index => $node) { 62 | if (FALSE === $node->getpeerinfo()) { 63 | echo "ERROR getting peer info from node $index\n"; 64 | echo "$node->error\n"; 65 | continue; 66 | } 67 | 68 | // if the node is connected to a peer to which another of our nodes is already connected, 69 | // instruct this node to disconnect from the peer 70 | $whitelistPeers = array(); 71 | foreach ($node->response['result'] as $peer) { 72 | if (array_key_exists($peer['addr'], $whitelist)) { 73 | $whitelistPeers[$peer['addr']] = TRUE; 74 | continue; 75 | } 76 | 77 | if (array_key_exists($peer['addr'], $connectedPeers)) { 78 | echo "Removing duplicate peer " . $peer['addr'] . "\n"; 79 | if (FALSE === $node->addnode($peer['addr'], 'disconnect')) { 80 | echo "ERROR instructing node $index to disconnect peer " . $peer['addr'] . "\n"; 81 | echo "$node->error\n"; 82 | } 83 | if (FALSE === $node->addnode($peer['addr'], 'remove')) { 84 | //echo "ERROR instructing node $index to remove peer " . $peer['addr'] . "\n"; 85 | //echo "$node->error\n"; 86 | } 87 | } else { 88 | $connectedPeers[$peer['addr']] = TRUE; 89 | } 90 | } 91 | 92 | // ensure that we are connected to all of the other nodes in our pool 93 | foreach ($whitelist as $ip => $value) { 94 | // don't try to connect a node to itself 95 | if ($ip == $config[$index]['ip'] . ':8333') { 96 | continue; 97 | } 98 | 99 | // don't instruct the node to connect to a whitelisted peer if it's already connected 100 | if (isset($whitelistPeers[$ip])) { 101 | continue; 102 | } 103 | 104 | echo "Instructing node $index to connect to whitelist peer $ip\n"; 105 | if (FALSE === $node->addnode($ip, 'onetry')) { 106 | echo "ERROR instructing node $index to connect to $ip\n"; 107 | echo "$node->error\n"; 108 | } 109 | if (FALSE === $node->addnode($ip, 'add')) { 110 | //echo "ERROR instructing node $index to add $ip\n"; 111 | //echo "$node->error\n"; 112 | } 113 | } 114 | } 115 | 116 | unlink(PID_FILE); 117 | -------------------------------------------------------------------------------- /nonRelayedTransactions/addPoolSlugs.php: -------------------------------------------------------------------------------- 1 | getBlock($json["block_hash"], 1); 71 | 72 | // get the mining pool for the given block 73 | //$pool = curl(); 74 | 75 | $missingTransactionCount = count($json["txids"]); 76 | $allBlocks[$block["height"]] = $missingTransactionCount; 77 | } 78 | 79 | 80 | // sort by block height ascending 81 | ksort($allBlocks); 82 | 83 | echo "Block Height,Missing Txns:\n"; 84 | foreach ($allBlocks as $height => $count) { 85 | echo "$height,$count\n"; 86 | } 87 | -------------------------------------------------------------------------------- /nonRelayedTransactions/findUnseenMempoolTransactions.php: -------------------------------------------------------------------------------- 1 | unseenTxs) || count($audit->unseenTxs) == 0) { 43 | $auditSummary == null; 44 | break; 45 | } 46 | 47 | if ($auditSummary == null) { 48 | $auditSummary = $audit; 49 | } else if (count($audit->unseenTxs) < count($auditSummary->unseenTxs)) { 50 | $auditSummary = $audit; 51 | } 52 | } 53 | 54 | if ($auditSummary == null) { 55 | continue; 56 | } 57 | 58 | $nonStandardCount = $opreturnCount = $inscriptionCount = 0; 59 | 60 | // get the pool that mined the block 61 | if (!array_key_exists($currentBlockHeight, $blockPools)) { 62 | $ch = curl_init(); 63 | curl_setopt($ch, CURLOPT_HEADER, 0); 64 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 65 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); 66 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); 67 | curl_setopt($ch, CURLOPT_URL, "https://mempool.space/api/v1/blocks/$currentBlockHeight"); 68 | 69 | $result = curl_exec($ch); 70 | $blocksJson = json_decode($result); 71 | 72 | foreach ($blocksJson as $block) { 73 | $blockPools[$block->height] = $block->extras->pool->slug; 74 | } 75 | } 76 | 77 | // get the tags for each unseen txn 78 | $ch = curl_init(); 79 | curl_setopt($ch, CURLOPT_HEADER, 0); 80 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 81 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); 82 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); 83 | curl_setopt($ch, CURLOPT_URL, "https://mempool.space/api/v1/block/$currentBlockHash/summary"); 84 | $result = curl_exec($ch); 85 | $resultJson = json_decode($result); 86 | foreach ($resultJson as $txn) { 87 | if (in_array($txn->txid, $auditSummary->unseenTxs)) { 88 | // mempool goggles bitfields documented at https://github.com/mempool/mempool/blob/485a58e45321d3c4f57b870811ce3e2b26be5f8f/frontend/src/app/shared/filters.utils.ts#L22-L59 89 | $binaryFlags = (string)decbin($txn->flags); 90 | if ($binaryFlags[-6] == "1") { // non-standard 91 | $nonStandardCount++; 92 | } 93 | if (strlen($binaryFlags) >= 25 && $binaryFlags[-25] == "1") { // OP_RETURN 94 | $opreturnCount++; 95 | } 96 | if (strlen($binaryFlags) >= 44 && $binaryFlags[-44] == "1") { // inscription 97 | $inscriptionCount++; 98 | } 99 | } 100 | } 101 | echo $auditSummary->height . "," . 102 | $auditSummary->id . "," . 103 | $blockPools[$currentBlockHeight] . "," . 104 | count($auditSummary->unseenTxs) . "," . 105 | $nonStandardCount . "," . 106 | $opreturnCount . "," . 107 | $inscriptionCount . "," . 108 | implode(",", $auditSummary->unseenTxs) . "\n"; 109 | } -------------------------------------------------------------------------------- /nonRelayedTransactions/getCoinmetricsTransactions.py: -------------------------------------------------------------------------------- 1 | from coinmetrics.api_client import CoinMetricsClient 2 | from datetime import timedelta 3 | 4 | client = CoinMetricsClient('API_KEY') 5 | 6 | if __name__ == '__main__': 7 | tx_tracker = client.get_transaction_tracker( 8 | asset='btc', 9 | start_time='2022-01-01T00:00:00Z', 10 | end_time='2024-01-01T00:00:00Z', 11 | page_size='10000' 12 | ).parallel(time_increment=timedelta(days=1)).export_to_csv_files(data_directory='./txhistory') 13 | 14 | ## To find the transactions that were not seen as unconfirmed, run the following in the txhistory directory: 15 | ## grep --invert-match UNCONFIRMED btc_transaction-tracker*.csv | grep --invert-match txid -------------------------------------------------------------------------------- /nonRelayedTransactions/mempoolAPIConsistencyCheck.php: -------------------------------------------------------------------------------- 1 | unseenTxs); 14 | if ($unseenTxs < $lowestValue) 15 | $lowestValue = $unseenTxs; 16 | } 17 | 18 | echo "$lowestValue\n"; -------------------------------------------------------------------------------- /realtimeHashrate/aggregateRealtimePoolStats.php: -------------------------------------------------------------------------------- 1 | getBlockchaininfo()->get('blocks'); 23 | $currentBlockHash = $bitcoind->getBlockhash($height)->get(); 24 | // initialize array of arrays 25 | $poolHashByBlockHeight = array(); // [blockHeight][pool] => hashrate 26 | for ($i = $startHeight; $i < $maxBlockHeight; $i++) { 27 | $poolHashByBlockHeight[$i] = array(); 28 | } 29 | 30 | // keep track of the last block height for which a realtime hashrate was bucketed 31 | // this will come in handy for our second pass across the data 32 | $lastBlockHeightSeen = array(); 33 | 34 | // for each block, find all of the unique reported realtime pool hash rates 35 | // that were collected most recently before that block's timestamp 36 | // note that, on occasion, a block's timestamp may be before the parent block's timestamp 37 | // and thus we should use the same set of realtime reported hashrates 38 | while ($height < $maxBlockHeight) { 39 | $currentBlock = $bitcoind->getBlockHeader($currentBlockHash); 40 | $currentBlockTime = $currentBlock->get('time'); 41 | 42 | // find most recent realtime hashrates 43 | // TSV file format: Row Number,Epoch Time (Seconds),Pool Name,Pool Hashrate (EH/s) 44 | while (true) { 45 | $data = fgetcsv($handle, 1000, "\t"); 46 | if ($data === FALSE) { // end of file 47 | break 2; 48 | } 49 | if ($data[3] == "\N") { // no data for this line 50 | continue; 51 | } 52 | 53 | if ($data[1] <= $currentBlockTime) { 54 | $poolHashByBlockHeight[$height][$data[2]] = $data[3]; 55 | $lastBlockHeightSeen[$data[2]] = $height; 56 | } else { // we've moved on to the next block bucket 57 | $poolHashByBlockHeight[$height + 1][$data[2]] = $data[3]; 58 | $lastBlockHeightSeen[$data[2]] = $height + 1; 59 | $height++; 60 | break; 61 | } 62 | } 63 | $currentBlockHash = $currentBlock->get('nextblockhash'); 64 | } 65 | 66 | // Now we have bucketed all of the realtime hashrate metrics, 67 | // however there are gaps in the buckets because the realtime 68 | // metrics were not collected at block-level time granularity 69 | // thus we need to fill in the gaps by populating each data point 70 | // forward into future buckets until we hit a freshly collected metric 71 | foreach ($poolHashByBlockHeight as $blockHeight => $pools) { 72 | // no more gaps to fill; prevent bug trying to access nonexistent array 73 | if ($blockHeight >= $maxBlockHeight) { 74 | break; 75 | } 76 | 77 | foreach ($pools as $pool => $hashrate) { 78 | $tmpBlockHeight = $blockHeight + 1; 79 | while (!array_key_exists($pool, $poolHashByBlockHeight[$tmpBlockHeight])) { 80 | if ($tmpBlockHeight >= $lastBlockHeightSeen[$pool]) 81 | break; 82 | $poolHashByBlockHeight[$tmpBlockHeight][$pool] = $hashrate; 83 | $tmpBlockHeight++; 84 | } 85 | } 86 | } 87 | 88 | // output CSV file format 89 | echo "Block Height,Aggregate Realtime Hashrate\n"; 90 | foreach ($poolHashByBlockHeight as $blockHeight => $pools) { 91 | $totalHashrate = 0; 92 | foreach ($pools as $pool => $hashrate) { 93 | $totalHashrate += $hashrate; 94 | } 95 | echo "$blockHeight,$totalHashrate\n"; 96 | } -------------------------------------------------------------------------------- /realtimeHashrate/blendedHashrateEstimate.php: -------------------------------------------------------------------------------- 1 | 6.23, 19 | 200 => 4.53, 20 | 300 => 3.85, 21 | 400 => 3.48, 22 | 500 => 3.24, 23 | 600 => 3.11, 24 | 700 => 3.04, 25 | 800 => 3.04, 26 | 900 => 3.01 27 | ); 28 | 29 | // Start off giving a 10% weight to the 1,100 trailing block estimate 30 | $longEstimate = $bitcoind->getNetworkHashPS(1100, $blockHeight)->get(); 31 | $blendedEstimate = $longEstimate * 0.1; 32 | 33 | for ($trailingBlocks = 100; $trailingBlocks < 1000; $trailingBlocks += 100) { 34 | $shortEstimate = $bitcoind->getNetworkHashPS($trailingBlocks, $blockHeight)->get(); 35 | 36 | // if current short hashrate estimate is less than 1 std deviation from long estimate, ignore it 37 | if (abs($longEstimate - $shortEstimate) < $estimateStdDev[$trailingBlocks]) { 38 | $blendedEstimate += $longEstimate * 0.1; 39 | } else { 40 | // find how many of the recent ($trailingBlocks) short estimates have also been above/below the long estimate 41 | // and weight the short estimate 42 | if ($shortEstimate > $longEstimate) { 43 | $higher = 0; 44 | for ($height = $blockHeight - $trailingBlocks; $height < $blockHeight; $height++) { 45 | if ($bitcoind->getNetworkHashPS($trailingBlocks, $height)->get() > $longEstimate) { 46 | $higher++; 47 | } 48 | } 49 | $shortWeight = $higher / $trailingBlocks; 50 | } else { 51 | $shortWeight = 0; 52 | } 53 | $blendedEstimate += ($longEstimate * (1 - $shortWeight) + $shortEstimate * $shortWeight) * 0.1; 54 | } 55 | } 56 | 57 | echo "$blendedEstimate\n"; -------------------------------------------------------------------------------- /realtimeHashrate/blendedHashrateEstimate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if an argument is provided and it's a numeric value 4 | if [ $# -lt 1 ] || ! [[ $1 =~ ^[0-9]+$ ]]; then 5 | echo "ERROR: argument 1 must be an integer" 6 | exit 1 7 | fi 8 | 9 | blockHeight="$1" 10 | 11 | declare -A estimateStdDev=( 12 | [100]=6.23 13 | [200]=4.53 14 | [300]=3.85 15 | [400]=3.48 16 | [500]=3.24 17 | [600]=3.11 18 | [700]=3.04 19 | [800]=3.04 20 | [900]=3.01 21 | ) 22 | 23 | # Start off giving a 10% weight to the 1,100 trailing block estimate 24 | longEstimate=$(bitcoin-cli getnetworkhashps 1100 "$blockHeight" | awk -FE 'BEGIN{OFMT="%20"} {print $1 * (10 ^ $2)}') 25 | blendedEstimate=$(echo "$longEstimate * 0.1" | bc -l) 26 | 27 | for ((trailingBlocks=100; trailingBlocks<1000; trailingBlocks+=100)); do 28 | shortEstimate=$(bitcoin-cli getnetworkhashps "$trailingBlocks" "$blockHeight" | awk -FE 'BEGIN{OFMT="%20"} {print $1 * (10 ^ $2)}') 29 | 30 | estimateDiff=$(bc -l <<< "$longEstimate - $shortEstimate") 31 | # if current short hashrate estimate is less than 1 std deviation from long estimate, ignore it 32 | if (( $(bc -l <<< "${estimateDiff#-} < ${estimateStdDev[$trailingBlocks]}") )); then 33 | blendedEstimate=$(echo "$blendedEstimate + $longEstimate * 0.1" | bc -l) 34 | else 35 | # find how many of the recent ($trailingBlocks) short estimates have also been above/below the long estimate 36 | # and weight the short estimate 37 | if ((shortEstimate > longEstimate)); then 38 | higher=0 39 | for ((height=blockHeight-trailingBlocks; height longEstimate )); then 41 | ((higher++)) 42 | fi 43 | done 44 | shortWeight=$(bc -l <<< "$higher / $trailingBlocks") 45 | else 46 | shortWeight=0 47 | fi 48 | blendedEstimate=$(echo "($longEstimate * (1 - $shortWeight) + $shortEstimate * $shortWeight) * 0.1 + $blendedEstimate" | bc -l) 49 | fi 50 | done 51 | 52 | echo "$blendedEstimate" 53 | -------------------------------------------------------------------------------- /realtimeHashrate/calculateAverageErrorRates.php: -------------------------------------------------------------------------------- 1 | $average) { 43 | echo "$trailingBlocks,$average\n"; 44 | } -------------------------------------------------------------------------------- /realtimeHashrate/calculateBlendedEstimateErrorRate.php: -------------------------------------------------------------------------------- 1 | 6.23, 38 | 200 => 4.53, 39 | 300 => 3.85, 40 | 400 => 3.48, 41 | 500 => 3.24, 42 | 600 => 3.11, 43 | 700 => 3.04, 44 | 800 => 3.04, 45 | 900 => 3.01 46 | ); 47 | 48 | // calculated results 49 | $blendedEstimates = array(); 50 | $errorRates = array(); 51 | $stdDeviations = array(); 52 | 53 | // CSV file format: Block Height, Realtime Aggregate Hashrate (EH/s) 54 | $handle = fopen($argv[11], "r"); 55 | while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 56 | $blockHeight = (integer)$data[0]; 57 | $hashrate = $data[1]; 58 | $realHashrates[$blockHeight] = $hashrate; 59 | } 60 | fclose($handle); 61 | 62 | // populate maps of all estimates 63 | for ($i = 1; $i <= 10; $i++) { 64 | // CSV file format: Block Height, Estimated Hashrate (EH/s) 65 | $handle = fopen($argv[$i], "r"); 66 | while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 67 | $blockHeight = (integer)$data[0]; 68 | $hashrate = $data[1]; 69 | $estimates[$i * 100][$blockHeight] = $hashrate; 70 | } 71 | fclose($handle); 72 | } 73 | 74 | // calculate blended hashrate estimate 75 | foreach ($realHashrates as $blockHeight => $hashrate) { 76 | // only start $trailingBlocks blocks into our data since we use a window of past $trailingBlocks blocks of estimates 77 | if ($blockHeight < $startHeight + 900) { 78 | continue; 79 | } 80 | 81 | $blendedEstimate = $estimates[1000][$blockHeight] * 0.10; 82 | for ($i = 1; $i < 10; $i++) { 83 | $shortEstimate = $estimates[$i * 100][$blockHeight]; 84 | $longEstimate = $estimates[1000][$blockHeight]; 85 | 86 | // if current short hashrate estimate is less than 1 std deviation from long estimate, ignore it 87 | if (abs($longEstimate - $shortEstimate) < $estimateStdDev[$i * 100]) { 88 | $blendedEstimate += $longEstimate * 0.1; 89 | } else { 90 | // find how many of the recent short estimates have also been above/below the long estimate 91 | // and weight the short estimate 92 | if ($shortEstimate > $longEstimate) { 93 | $higher = 0; 94 | for ($height = $blockHeight - $i * 100; $height < $blockHeight; $height++) { 95 | if ($estimates[$i * 100][$height] > $estimates[1000][$height]) { 96 | $higher++; 97 | } 98 | } 99 | $shortWeight = $higher / ($i * 100); 100 | } else { 101 | $lower = 0; 102 | for ($height = $blockHeight - $i * 100; $height < $blockHeight; $height++) { 103 | if ($estimates[$i * 100][$height] < $estimates[1000][$height]) { 104 | $lower++; 105 | } 106 | } 107 | 108 | //$shortWeight = $lower / ($i * 100); 109 | $shortWeight = 0; 110 | } 111 | $blendedEstimate += ($longEstimate * (1 - $shortWeight) + $shortEstimate * $shortWeight) * 0.1; 112 | } 113 | } 114 | $blendedEstimates[$blockHeight] = $blendedEstimate; 115 | 116 | // calculate the relative error rates for the new blended estimates 117 | $errorRate = number_format(abs($realHashrates[$blockHeight] - $blendedEstimate) / $realHashrates[$blockHeight], 2, '.', '') * 100; 118 | $errorRates[$blockHeight] = $errorRate; 119 | } 120 | 121 | // calculate the average error for the new blended estimates 122 | $sum = array_sum($errorRates); 123 | $count = count($errorRates); 124 | $average = $sum / $count; 125 | 126 | // calculate the standard deviation for the new blended estimates 127 | $deviationSquares = array(); 128 | foreach ($errorRates as $errorRate) { 129 | $deviationSquares[] = ($errorRate - $average) ** 2; 130 | } 131 | 132 | $stdDeviation = sqrt(array_sum($deviationSquares) / $count); 133 | //foreach ($blendedEstimates as $blockHeight => $hashrate) { 134 | // echo "$blockHeight,$hashrate\n"; 135 | //} 136 | echo "Average Error Rate,Standard Deviation\n"; 137 | echo "$average,$stdDeviation\n"; -------------------------------------------------------------------------------- /realtimeHashrate/calculateRelativeErrorRates.php: -------------------------------------------------------------------------------- 1 | getNetworkHashPS($trailingBlocks, $blockHeight)->get(); 39 | // use hashrate in exahashes with 2 decimals precison 40 | $exaHashrate = number_format($hashrate / 1E+18, 2, '.', ''); 41 | $errorRate = number_format(abs($realHashrate - $exaHashrate) / $realHashrate, 2, '.', '') * 100; 42 | $errorRates[$trailingBlocks][$blockHeight] = $errorRate; 43 | } 44 | } 45 | 46 | echo "Trailing Blocks,Block Height,Error %\n"; 47 | foreach ($errorRates as $trailingBlocks => $rates) { 48 | foreach ($rates as $blockHeight => $errorRate) { 49 | echo "$trailingBlocks,$blockHeight,$errorRate\n"; 50 | } 51 | } -------------------------------------------------------------------------------- /realtimeHashrate/calculateStandardDeviationErrorRates.php: -------------------------------------------------------------------------------- 1 | $deviation) { 58 | echo "$trailingBlocks,$deviation\n"; 59 | } -------------------------------------------------------------------------------- /realtimeHashrate/iterate100BlockEstimateWeights.php: -------------------------------------------------------------------------------- 1 | $hashrate) { 90 | // only start $trailingBlocks blocks into our data since we use a window of past $trailingBlocks blocks of estimates 91 | if ($blockHeight < $startHeight + $trailingBlocks) { 92 | continue; 93 | } 94 | $shortEstimate = $shortEstimates[$blockHeight]; 95 | $longEstimate = $longEstimates[$blockHeight]; 96 | 97 | // if current short hashrate estimate is less than 1 std deviation from long estimate, ignore it 98 | if (abs($longEstimate - $shortEstimate) / $longEstimate < 0.06) { 99 | $blendedEstimate = $longEstimate; 100 | } else { 101 | $shortWeight = 0; 102 | 103 | // find how many of the recent short estimates have also been above/below the long estimate 104 | // and weight the short estimate 105 | if ($shortEstimate > $longEstimate) { 106 | $higher = 0; 107 | for ($i = $blockHeight - $trailingBlocks; $i < $blockHeight; $i++) { 108 | if ($shortEstimates[$i] > $longEstimates[$i]) { 109 | $higher++; 110 | } 111 | } 112 | $shortWeight = $higher / $higherShortWeight; 113 | } else { 114 | $lower = 0; 115 | for ($i = $blockHeight - $trailingBlocks; $i < $blockHeight; $i++) { 116 | if ($shortEstimates[$i] < $longEstimates[$i]) { 117 | $lower++; 118 | } 119 | } 120 | // TODO exclude if it was only lower the vast majority of the period 121 | $shortWeight = $lower / $lowerShortWeight; 122 | } 123 | $blendedEstimate = $longEstimate * (1 - $shortWeight) + $shortEstimate * $shortWeight; 124 | } 125 | $blendedEstimates[$blockHeight] = $blendedEstimate; 126 | 127 | // calculate the relative error rates for the new blended estimates 128 | $errorRate = number_format(abs($realHashrates[$blockHeight] - $blendedEstimate) / $realHashrates[$blockHeight], 2, '.', '') * 100; 129 | $errorRates[$blockHeight] = $errorRate; 130 | } 131 | 132 | // calculate the average error for the new blended estimates 133 | $sum = array_sum($errorRates); 134 | $count = count($errorRates); 135 | $average = $sum / $count; 136 | 137 | // calculate the standard deviation for the new blended estimates 138 | $deviationSquares = array(); 139 | foreach ($errorRates as $errorRate) { 140 | $deviationSquares[] = ($errorRate - $average) ** 2; 141 | } 142 | 143 | $stdDeviation = sqrt(array_sum($deviationSquares) / $count); 144 | //foreach ($blendedEstimates as $blockHeight => $hashrate) { 145 | //echo "$blockHeight,$hashrate\n"; 146 | //} 147 | echo "$trailingBlocks,$higherShortWeight,$lowerShortWeight,$average,$stdDeviation\n"; 148 | } 149 | } 150 | } -------------------------------------------------------------------------------- /realtimeHashrate/outputEstimatedHashratePerBlock.php: -------------------------------------------------------------------------------- 1 | 2000) { 10 | echo "ERROR: first argument must be an integer for trailing number of blocks used to estimate hashrate\n"; 11 | exit; 12 | } 13 | 14 | $bitcoind = new BitcoinClient('http://user:pass@localhost:8332/'); 15 | $startHeight = $height = 713762; // start height of realtime data 16 | $maxBlockHeight = $bitcoind->getBlockchaininfo()->get('blocks'); 17 | $trailingBlocks = (int)$argv[1]; 18 | 19 | echo "Block Height,Hashrate Estimate $trailingBlocks Blocks\n"; 20 | while ($height < $maxBlockHeight) { 21 | $hashrate = $bitcoind->getNetworkHashPS($trailingBlocks, $height)->get(); 22 | // store hashrate in exahashes with 2 decimals precison 23 | $exaHashrate = number_format($hashrate / 1E+18, 2); 24 | echo "$height,$exaHashrate\n"; 25 | $height++; 26 | } -------------------------------------------------------------------------------- /regtest-network/networkSimulator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) 2014 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | # Create 4 nodes and have them generate blocks and forks 7 | 8 | set -f 9 | 10 | BITCOIND=/usr/local/bin/bitcoind 11 | CLI=/usr/local/bin/bitcoin-cli 12 | 13 | DIR="${BASH_SOURCE%/*}" 14 | SENDANDWAIT="${DIR}/send.sh" 15 | if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi 16 | . "$DIR/util.sh" 17 | 18 | D=$(mktemp -d /tmp/test.XXXXX) 19 | 20 | # Create four nodes 21 | 22 | D1=${D}/node1 23 | CreateDataDir $D1 port=18444 rpcport=12001 24 | B1ARGS="-datadir=$D1 -debug=mempool" 25 | $BITCOIND $B1ARGS & 26 | B1PID=$! 27 | 28 | D2=${D}/node2 29 | CreateDataDir $D2 port=18445 rpcport=12002 30 | B2ARGS="-datadir=$D2 -debug=mempool" 31 | $BITCOIND $B2ARGS & 32 | B2PID=$! 33 | 34 | D3=${D}/node3 35 | CreateDataDir $D3 port=18446 rpcport=12003 36 | B3ARGS="-datadir=$D3 -debug=mempool" 37 | $BITCOIND $B3ARGS & 38 | B3PID=$! 39 | 40 | D4=${D}/node4 41 | CreateDataDir $D4 port=18447 rpcport=12004 42 | B4ARGS="-datadir=$D4 -debug=mempool" 43 | $BITCOIND $B4ARGS & 44 | B4PID=$! 45 | 46 | # Wait until all four nodes are at the same block number 47 | function WaitBlocks { 48 | while : 49 | do 50 | sleep 1 51 | declare -i BLOCKS1=$( GetBlocks $B1ARGS ) 52 | declare -i BLOCKS2=$( GetBlocks $B2ARGS ) 53 | declare -i BLOCKS3=$( GetBlocks $B3ARGS ) 54 | declare -i BLOCKS4=$( GetBlocks $B4ARGS ) 55 | if (( BLOCKS1 == BLOCKS2 && BLOCKS2 == BLOCKS3 && BLOCKS3 == BLOCKS4)) 56 | then 57 | break 58 | fi 59 | echo "Waiting for block heights to sync across nodes" 60 | done 61 | } 62 | 63 | # Wait until node has $N peers 64 | function WaitPeers { 65 | while : 66 | do 67 | declare -i PEERS=$( $CLI $1 getconnectioncount ) 68 | if (( PEERS >= "$2" )) 69 | then 70 | break 71 | fi 72 | echo "Waiting for node $1 to reach $2 peers" 73 | sleep 1 74 | done 75 | } 76 | 77 | # Disconnect node $1, generate blocks & txs, reconnect to peers 78 | function GenerateFork { 79 | BARGS="B${1}ARGS" 80 | BARGS="${!BARGS}" 81 | BPID="B${1}PID" 82 | BPID="${!BPID}" 83 | 84 | # send 1 BTC to every node from node 1; txs will be mined on both forks 85 | FundAllNodes 1 86 | 87 | # restart node $1 with no connection 88 | $CLI $BARGS stop > /dev/null 2>&1 89 | wait $BPID 90 | $BITCOIND $BARGS & 91 | let B${1}PID="$!" 92 | 93 | # send 1 BTC to every node from node 1; 3 txs will be mined on orphan fork 94 | FundAllNodes 1 95 | 96 | # Send 1 BTC from node N to node 1; tx will be mined on new longer fork 97 | B1ADDRESS=$( $CLI $B1ARGS getnewaddress ) 98 | TX=$( $CLI $BARGS sendtoaddress $B1ADDRESS 1.0) 99 | 100 | # generate blocks on every node but generate a longer chain on node $N 101 | $CLI $B1ARGS setgenerate true 1 102 | $CLI $B2ARGS setgenerate true 2 103 | $CLI $B3ARGS setgenerate true 3 104 | $CLI $B4ARGS setgenerate true 4 105 | $CLI $BARGS setgenerate true 10 106 | 107 | #reconnect node $N to node 1 108 | $CLI $BARGS addnode 127.0.0.1:18444 onetry 109 | WaitPeers "$BARGS" 1 110 | } 111 | 112 | # Sends $N BTC from Node 1 to every other node & mines a block to confirm the txs 113 | function FundAllNodes { 114 | B2ADDRESS=$( $CLI $B2ARGS getnewaddress ) 115 | B3ADDRESS=$( $CLI $B3ARGS getnewaddress ) 116 | B4ADDRESS=$( $CLI $B4ARGS getnewaddress ) 117 | 118 | # send N BTC to every node from node 1 119 | TX1=$( $CLI $B1ARGS sendtoaddress $B2ADDRESS ${1}) 120 | TX2=$( $CLI $B1ARGS sendtoaddress $B3ADDRESS ${1}) 121 | TX3=$( $CLI $B1ARGS sendtoaddress $B4ADDRESS ${1}) 122 | 123 | # confirm the txs 124 | $CLI $B1ARGS setgenerate true 1 125 | } 126 | 127 | # Sends $N BTC from each node to a different node 128 | function SendRandomTransactions { 129 | B1ADDRESS=$( $CLI $B1ARGS getnewaddress ) 130 | B2ADDRESS=$( $CLI $B2ARGS getnewaddress ) 131 | B3ADDRESS=$( $CLI $B3ARGS getnewaddress ) 132 | B4ADDRESS=$( $CLI $B4ARGS getnewaddress ) 133 | 134 | # send N BTC to every node from node 1 135 | TX1=$( $CLI $B1ARGS sendtoaddress $B2ADDRESS ${1}) 136 | TX2=$( $CLI $B2ARGS sendtoaddress $B3ADDRESS ${1}) 137 | TX3=$( $CLI $B3ARGS sendtoaddress $B4ADDRESS ${1}) 138 | TX4=$( $CLI $B4ARGS sendtoaddress $B2ADDRESS ${1}) 139 | } 140 | 141 | echo "Started four regtest nodes" 142 | 143 | # start building chain on node 1 144 | $CLI $B1ARGS setgenerate true 2 145 | 146 | # connect B2 to B1: 147 | $CLI $B2ARGS addnode 127.0.0.1:18444 onetry 148 | WaitPeers "$B1ARGS" 1 149 | 150 | # connect B3 to B1: 151 | $CLI $B3ARGS addnode 127.0.0.1:18444 onetry 152 | 153 | # connect B4 to B1: 154 | $CLI $B4ARGS addnode 127.0.0.1:18444 onetry 155 | 156 | # ensure all peers are connected 157 | WaitPeers "$B1ARGS" 3 158 | WaitPeers "$B2ARGS" 1 159 | WaitPeers "$B3ARGS" 1 160 | WaitPeers "$B4ARGS" 1 161 | WaitBlocks 162 | 163 | echo "Generating network activity!" 164 | sleep 4 # give indexer a few seconds to get out of bulk load mode 165 | 166 | # generate 120 blocks on node 1 so that we can spend coinbase outputs 167 | $CLI $B1ARGS setgenerate true 200 168 | WaitBlocks 169 | FundAllNodes 1000 # prevent insufficient funds errors when sending future txs 170 | $CLI $B1ARGS setgenerate true 20 171 | WaitBlocks 172 | 173 | # begin generating forks and random txs 174 | for i in `seq 1 10`; 175 | do 176 | GenerateFork 2 177 | $CLI $B1ARGS setgenerate true 2 178 | WaitBlocks 179 | SendRandomTransactions 2 180 | $CLI $B2ARGS setgenerate true 2 181 | SendRandomTransactions 3 182 | $CLI $B3ARGS setgenerate true 2 183 | WaitBlocks 184 | $CLI $B4ARGS setgenerate true 2 185 | GenerateFork 3 186 | WaitBlocks 187 | $CLI $B4ARGS setgenerate true 2 188 | SendRandomTransactions 4 189 | WaitBlocks 190 | GenerateFork 4 191 | WaitBlocks 192 | GenerateFork 3 193 | WaitBlocks 194 | SendRandomTransactions 1 195 | $CLI $B3ARGS setgenerate true 2 196 | GenerateFork 2 197 | GenerateFork 4 198 | GenerateFork 2 199 | sleep 10 200 | done 201 | 202 | $CLI $B4ARGS setgenerate true 100 203 | 204 | echo "Regtest nodes will shut down in 30 seconds" 205 | sleep 30 206 | 207 | $CLI $B4ARGS stop > /dev/null 2>&1 208 | wait $B4PID 209 | $CLI $B3ARGS stop > /dev/null 2>&1 210 | wait $B3PID 211 | $CLI $B2ARGS stop > /dev/null 2>&1 212 | wait $B2PID 213 | $CLI $B1ARGS stop > /dev/null 2>&1 214 | wait $B1PID 215 | 216 | echo "Tests successful, cleaning up" 217 | rm -rf $D 218 | exit 0 219 | -------------------------------------------------------------------------------- /regtest-network/send.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2014 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | TIMEOUT=10 6 | SIGNAL=HUP 7 | PIDFILE=.send.pid 8 | if [ $# -eq 0 ]; then 9 | echo -e "Usage:\t$0 " 10 | echo -e "\tRuns and wait ${TIMEOUT} seconds or until SIG${SIGNAL} is received." 11 | echo -e "\tReturns: 0 if SIG${SIGNAL} is received, 1 otherwise." 12 | echo -e "Or:\t$0 -STOP" 13 | echo -e "\tsends SIG${SIGNAL} to running send.sh" 14 | exit 0 15 | fi 16 | 17 | if [ $1 = "-STOP" ]; then 18 | if [ -s ${PIDFILE} ]; then 19 | kill -s ${SIGNAL} $(<$PIDFILE 2>/dev/null) 2>/dev/null 20 | fi 21 | exit 0 22 | fi 23 | 24 | trap '[[ ${PID} ]] && kill ${PID}' ${SIGNAL} 25 | trap 'rm -f ${PIDFILE}' EXIT 26 | echo $$ > ${PIDFILE} 27 | "$@" 28 | sleep ${TIMEOUT} & PID=$! 29 | wait ${PID} && exit 1 30 | 31 | exit 0 32 | -------------------------------------------------------------------------------- /regtest-network/util.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) 2014 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | # Functions used by more than one test 7 | 8 | function echoerr { 9 | echo "$@" 1>&2; 10 | } 11 | 12 | # Usage: ExtractKey "" 13 | # Warning: this will only work for the very-well-behaved 14 | # JSON produced by bitcoind, do NOT use it to try to 15 | # parse arbitrary/nested/etc JSON. 16 | function ExtractKey { 17 | echo $2 | tr -d ' "{}\n' | awk -v RS=',' -F: "\$1 ~ /$1/ { print \$2}" 18 | } 19 | 20 | function CreateDataDir { 21 | DIR=$1 22 | mkdir -p $DIR 23 | CONF=$DIR/bitcoin.conf 24 | echo "regtest=1" >> $CONF 25 | echo "keypool=2" >> $CONF 26 | echo "rpcuser=rt" >> $CONF 27 | echo "rpcpassword=rt" >> $CONF 28 | echo "rpcwait=1" >> $CONF 29 | echo "walletnotify=${SENDANDWAIT} -STOP" >> $CONF 30 | shift 31 | while (( "$#" )); do 32 | echo $1 >> $CONF 33 | shift 34 | done 35 | } 36 | 37 | function AssertEqual { 38 | if (( $( echo "$1 == $2" | bc ) == 0 )) 39 | then 40 | echoerr "AssertEqual: $1 != $2" 41 | declare -f CleanUp > /dev/null 2>&1 42 | if [[ $? -eq 0 ]] ; then 43 | CleanUp 44 | fi 45 | exit 1 46 | fi 47 | } 48 | 49 | # CheckBalance -datadir=... amount account minconf 50 | function CheckBalance { 51 | declare -i EXPECT="$2" 52 | B=$( $CLI $1 getbalance $3 $4 ) 53 | if (( $( echo "$B == $EXPECT" | bc ) == 0 )) 54 | then 55 | echoerr "bad balance: $B (expected $2)" 56 | declare -f CleanUp > /dev/null 2>&1 57 | if [[ $? -eq 0 ]] ; then 58 | CleanUp 59 | fi 60 | exit 1 61 | fi 62 | } 63 | 64 | # Use: Address [account] 65 | function Address { 66 | $CLI $1 getnewaddress $2 67 | } 68 | 69 | # Send from to amount 70 | function Send { 71 | from=$1 72 | to=$2 73 | amount=$3 74 | address=$(Address $to) 75 | txid=$( ${SENDANDWAIT} $CLI $from sendtoaddress $address $amount ) 76 | } 77 | 78 | # Use: Unspent 79 | function Unspent { 80 | local r=$( $CLI $1 listunspent | awk -F'[ |:,"]+' "\$2 ~ /$3/ { print \$3 }" | tail -n $2 | head -n 1) 81 | echo $r 82 | } 83 | 84 | # Use: CreateTxn1 85 | # produces hex from signrawtransaction 86 | function CreateTxn1 { 87 | TXID=$(Unspent $1 $2 txid) 88 | AMOUNT=$(Unspent $1 $2 amount) 89 | VOUT=$(Unspent $1 $2 vout) 90 | RAWTXN=$( $CLI $1 createrawtransaction "[{\"txid\":\"$TXID\",\"vout\":$VOUT}]" "{\"$3\":$AMOUNT}") 91 | ExtractKey hex "$( $CLI $1 signrawtransaction $RAWTXN )" 92 | } 93 | 94 | # Use: SendRawTxn 95 | function SendRawTxn { 96 | ${SENDANDWAIT} $CLI $1 sendrawtransaction $2 97 | } 98 | 99 | # Use: GetBlocks 100 | # returns number of blocks from getinfo 101 | function GetBlocks { 102 | $CLI $1 getblockcount 103 | } 104 | -------------------------------------------------------------------------------- /slush_pool_history/dumpSlushpoolHistoricalStats.php: -------------------------------------------------------------------------------- 1 | data->btc->blocks->items->$items->data->data; 32 | /* 33 | [0] => id 34 | [1] => found_at 35 | [2] => duration 36 | [3] => total_shares 37 | [4] => value 38 | [5] => height 39 | [6] => difficulty 40 | [7] => hash 41 | [8] => luck_perc 42 | [9] => pool_scoring_hashrate 43 | [10] => state 44 | [11] => to_confirm 45 | */ 46 | foreach ($page as $data) { 47 | echo "$data[5],$data[1],$data[4],$data[9]\n"; 48 | } 49 | sleep(1); 50 | } 51 | curl_close($ch); -------------------------------------------------------------------------------- /slush_pool_history/estimateHistoricalPayouts.php: -------------------------------------------------------------------------------- 1 | $maxHeight) { 47 | continue; 48 | } 49 | if ($height < $minHeight) { 50 | // no more blocks in range 51 | break; 52 | } 53 | $blockValue = $data[2]; 54 | $poolHashrate = $data[3]; 55 | 56 | // If this is a forward-looking projection when user was not actually mining, 57 | // we must add their expected hashrate contribution to the pool's reported hashrate 58 | if ($future) { 59 | // calculate the expected miner hashrate by factoring in depreciation due to hardware failure 60 | // we model a 15% annual failure rate which equates to 1.25% hashpower loss ever 4,380 blocks if applied monthly 61 | $minerHashrate = $startingHashrate * 0.9875 ** floor(($height - $minHeight) / 4380); 62 | $poolHashrate += $minerHashrate; 63 | } 64 | 65 | // Expected revenue is this miner's % of the pool hashrate time the reward, minus the pool's 2% fee 66 | $estimatedRevenueForBlock = number_format((($minerHashrate / $poolHashrate) * $blockValue) * 0.98, 8, '.', ''); 67 | $totalRevenue += $estimatedRevenueForBlock; 68 | $date = gmdate("m-d-Y",$data[1]); 69 | if (isset($earningsByDate[$date])) { 70 | $earningsByDate[$date] += $estimatedRevenueForBlock; 71 | } else { 72 | $earningsByDate[$date] = $estimatedRevenueForBlock; 73 | } 74 | $hashrateByDate[$date] = $minerHashrate; 75 | echo "$height,$date,$estimatedRevenueForBlock,$minerHashrate\n"; 76 | } 77 | } else { 78 | echo "ERROR: Failed to open CSV file\n"; 79 | } 80 | fclose($handle); 81 | 82 | echo "Date,Expected Revenue,Projected Hashrate\n"; 83 | foreach ($earningsByDate as $date => $revenue) { 84 | echo "$date,$revenue," . $hashrateByDate[$date] . "\n"; 85 | } 86 | echo "Estimated total revenue for range is: $totalRevenue\n"; -------------------------------------------------------------------------------- /systemMetricsDaemon.py: -------------------------------------------------------------------------------- 1 | # This daemon requires django, the python statsd library, and PSUtil: https://github.com/giampaolo/psutil 2 | # The daemon reads system metrics and outputs them to StatsD 3 | # Usage: python systemMetricsDaemon.py & 4 | 5 | import time 6 | from django.conf import settings 7 | from django.core.management.base import BaseCommand 8 | import psutil 9 | from statsd import StatsClient 10 | statsd = StatsClient() 11 | sleep_seconds = 10 12 | 13 | last_cpu = psutil.cpu_times() 14 | last_cpu_stats = psutil.cpu_stats() 15 | last_swap = psutil.swap_memory() 16 | last_disk_io = psutil.disk_io_counters() 17 | last_net_io = psutil.net_io_counters() 18 | 19 | time.sleep(sleep_seconds) 20 | 21 | def io_change(last, current): 22 | return dict([(f, (getattr(current, f) - getattr(last, f)) / sleep_seconds) 23 | for f in last._fields]) 24 | 25 | while True: 26 | 27 | cpu = psutil.cpu_times() 28 | cpu_change = io_change(last_cpu, cpu) 29 | cpu_stats = psutil.cpu_stats() 30 | cpu_stats_change = io_change(last_cpu_stats, cpu_stats) 31 | memory = psutil.virtual_memory() 32 | swap = psutil.swap_memory() 33 | swap_change = io_change(last_swap, swap) 34 | disk = psutil.disk_usage("/") 35 | disk_io = psutil.disk_io_counters() 36 | disk_io_change = io_change(last_disk_io, disk_io) 37 | net_io = psutil.net_io_counters() 38 | net_io_change = io_change(last_net_io, net_io) 39 | uptime = time.time() - psutil.boot_time() 40 | 41 | last_cpu = cpu 42 | last_cpu_stats = cpu_stats 43 | last_disk_io = disk_io 44 | last_swap = swap 45 | last_net_io = net_io 46 | 47 | gauges = { 48 | "system.memory.used": memory.used, 49 | "system.memory.free": memory.free, 50 | "system.memory.percent": memory.percent, 51 | "system.memory.available": memory.available, 52 | "system.memory.active": memory.active, 53 | "system.memory.inactive": memory.inactive, 54 | "system.memory.cached": memory.cached, 55 | "system.memory.buffers": memory.buffers, 56 | "system.memory.shared": memory.shared, 57 | "system.swap.used": swap.used, 58 | "system.swap.free": swap.free, 59 | "system.swap.percent": swap.percent, 60 | "system.swap.sin": swap_change["sin"], 61 | "system.swap.sout": swap_change["sout"], 62 | "system.cpu.user": cpu_change["user"], 63 | "system.cpu.nice": cpu_change["nice"], 64 | "system.cpu.system": cpu_change["system"], 65 | "system.cpu.idle": cpu_change["idle"], 66 | "system.cpu.iowait": cpu_change["iowait"], 67 | "system.cpu.percent": psutil.cpu_percent(), 68 | "system.cpu.context_switches": cpu_stats_change["ctx_switches"], 69 | "system.cpu.interrupts": cpu_stats_change["interrupts"], 70 | "system.cpu.soft_interrupts": cpu_stats_change["soft_interrupts"], 71 | "system.cpu.syscalls": cpu_stats_change["syscalls"], 72 | "system.load": psutil.getloadavg()[0], 73 | "system.disk.size.used": disk.used, 74 | "system.disk.size.free": disk.free, 75 | "system.disk.size.percent": disk.percent, 76 | "system.disk.read.bytes": disk_io_change["read_bytes"], 77 | "system.disk.read.count": disk_io_change["read_count"], 78 | "system.disk.read.merged_count": disk_io_change["read_merged_count"], 79 | "system.disk.read.time": disk_io_change["read_time"], 80 | "system.disk.write.bytes": disk_io_change["write_bytes"], 81 | "system.disk.write.count": disk_io_change["write_count"], 82 | "system.disk.write.merged_count": disk_io_change["write_merged_count"], 83 | "system.disk.write.time": disk_io_change["write_time"], 84 | "system.disk.busy_time": disk_io_change["busy_time"], 85 | "system.net.in.packets": net_io_change["packets_recv"], 86 | "system.net.in.bytes": net_io_change["bytes_recv"], 87 | "system.net.in.errors": net_io_change["errin"], 88 | "system.net.in.dropped": net_io_change["dropin"], 89 | "system.net.out.packets": net_io_change["packets_sent"], 90 | "system.net.out.bytes": net_io_change["bytes_sent"], 91 | "system.net.out.errors": net_io_change["errout"], 92 | "system.net.out.dropped": net_io_change["dropout"], 93 | "system.uptime": uptime, 94 | } 95 | 96 | for name, value in gauges.items(): 97 | statsd.gauge(name, value) 98 | 99 | time.sleep(sleep_seconds) 100 | -------------------------------------------------------------------------------- /testnetBlockStormTrigger.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script is designed to trigger a permanent difficulty reset of Bitcoin's testnet 3 | # to the minimum difficulty of 1 by ensuring that the block right before a difficulty 4 | # adjustment has a difficulty target of 1. 5 | # For more info see https://blog.lopp.net/the-block-storms-of-bitcoins-testnet/ 6 | 7 | pgrep -fl bfgminer 8 | # if not found - equals to 1, start it 9 | if [ $? -eq 1 ] 10 | then 11 | height=$(~/code/bitcoin/src/bitcoin-cli getblockcount) 12 | remainder=$(($height % 2016)) 13 | if [ $remainder -ge 2013 ] 14 | then 15 | ~/code/bfgminer/bfgminer -S opencl:auto -o http://127.0.0.1:18332 -u user -p password --generate-to mwnsh33QHVXYDLWUvZwRizzp72SEaRLnf2 --coinbase-sig "Mined by Lopp (⌐■_■)" & 16 | sleep 60 17 | pkill bfgminer 18 | else 19 | echo "too soon!" 20 | exit 21 | fi 22 | else 23 | echo "bfgminer running - do nothing" 24 | exit; 25 | fi 26 | -------------------------------------------------------------------------------- /trackUserAgentLongevity.php: -------------------------------------------------------------------------------- 1 | $userAgents) { 20 | // history starts at June 7 2014; Bitcoin Core 0.9 was released March 2014 and 0.10 was released Feb 2015 21 | // as such, only start tracking user agent history starting with Bitcoin Core 0.10 22 | if ($timestamp < 1418428800) { 23 | continue; 24 | } 25 | 26 | foreach ($userAgents as $userAgent => $count) { 27 | // Only count Bitcoin Core useragents 28 | if (!str_starts_with($userAgent, 'Satoshi:')) { 29 | continue; 30 | } 31 | 32 | // Only count useragents with 10+ nodes 33 | if ($count < 10) { 34 | continue; 35 | } 36 | 37 | // Only store Bitcoin Core Version 38 | $userAgent = substr($userAgent, 8); 39 | 40 | // remove versions < 0.10 because we don't have their full lifecycle history 41 | if (version_compare($userAgent, '0.10') == -1) { 42 | continue; 43 | } 44 | 45 | // ignore versions ending in ".99" because those are master branch builds 46 | if (str_ends_with($userAgent, '.99') || str_ends_with($userAgent, '.99.0')) { 47 | continue; 48 | } 49 | 50 | // ignore versions > 1.0 and < 20.0 as those aren't Bitcoin Core releases 51 | if (version_compare($userAgent, '1.0.0') >= 0 && version_compare($userAgent, '20.0') < 0) { 52 | continue; 53 | } 54 | 55 | // bucket this user agent's count based upon how many snapshots (weeks) it has been since first seen 56 | if (isset($userAgentLongevity[$userAgent])) { 57 | array_push($userAgentLongevity[$userAgent], array($timestamp, $count)); 58 | } else { 59 | $userAgentLongevity[$userAgent] = array(array($timestamp, $count)); 60 | } 61 | } 62 | } 63 | 64 | // print a CSV we can use to draw some charts 65 | echo "Week," . implode(',', array_keys($userAgentLongevity)) . "\n"; 66 | for ($week = 0; $week < 200; $week++) { 67 | echo "$week,"; 68 | foreach ($userAgentLongevity as $snapshot) { 69 | if (isset($snapshot[$week])) { 70 | echo $snapshot[$week][1]; 71 | } else { 72 | echo "0"; 73 | } 74 | echo ","; 75 | } 76 | echo "\n"; 77 | } 78 | 79 | // find peak node count for each user agent and determine 80 | // how many weeks it took for 95% of those nodes to upgrade versions 81 | foreach ($userAgentLongevity as $version => $snapshots) { 82 | 83 | $maxCount = 0; 84 | $maxWeek = 0; 85 | $totalWeeks = 0; 86 | foreach ($snapshots as $week => $snapshot) { 87 | if ($snapshot[1] > $maxCount) { 88 | $maxCount = $snapshot[1]; 89 | $maxWeek = $week; 90 | } 91 | } 92 | 93 | // find the first week at which count is <= 5% of $maxCount 94 | foreach ($snapshots as $week => $snapshot) { 95 | if ($week < $maxWeek) { 96 | continue; 97 | } 98 | if ($snapshot[1] <= $maxCount*0.05) { 99 | $totalWeeks = $week - $maxWeek; 100 | break; 101 | } 102 | } 103 | 104 | echo "$version, $totalWeeks\n"; 105 | } --------------------------------------------------------------------------------