#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const uint8_t hexDigits[] = "0123456789abcdef"; const uint8_t b58Digits[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; template<> uint8_t *PagedAllocator::pool = 0; template<> uint8_t *PagedAllocator::poolEnd = 0; template<> uint8_t *PagedAllocator::pool = 0; template<> uint8_t *PagedAllocator::poolEnd = 0; template<> uint8_t *PagedAllocator::pool = 0; template<> uint8_t *PagedAllocator::poolEnd = 0; template<> uint8_t *PagedAllocator::pool = 0; template<> uint8_t *PagedAllocator::poolEnd = 0; void toHex( uint8_t *dst, // 2*size +1 const uint8_t *src, // size size_t size, bool rev ) { int incr = 1; const uint8_t *p = src; const uint8_t *e = size + src; if(rev) { p = e-1; e = src-1; incr = -1; } while(likely(p!=e)) { uint8_t c = p[0]; dst[0] = hexDigits[c>>4]; dst[1] = hexDigits[c&0xF]; p += incr; dst += 2; } dst[0] = 0; } void showHex( const uint8_t *p, size_t size, bool rev ) { uint8_t* buf = (uint8_t*)alloca(2*size + 1); toHex(buf, p, size, rev); printf("%s", buf); } uint8_t fromHexDigit( uint8_t h, bool abortOnErr ) { if(likely('0'<=h && h<='9')) return (h - '0'); if(likely('a'<=h && h<='f')) return 10 + (h - 'a'); if(likely('A'<=h && h<='F')) return 10 + (h - 'A'); if(abortOnErr) errFatal("incorrect hex digit %c", h); return 0xFF; } bool fromHex( uint8_t *dst, const uint8_t *src, size_t dstSize, bool rev, bool abortOnErr ) { int incr = 2; uint8_t *end = dstSize + dst; if(rev) { src += 2*(dstSize-1); incr = -2; } while(likely(dst &addresses, int m, int n ) { std::sort( addresses.begin(), addresses.end(), Compare160() ); std::vector data; data.reserve(2 + kRIPEMD160ByteSize*sizeof(addresses)); data.push_back((uint8_t)m); data.push_back((uint8_t)n); for(const auto &addr:addresses) { data.insert( data.end(), addr.v, kRIPEMD160ByteSize + addr.v ); } rmd160( pubKeyHash, &(data[0]), data.size() ); } // Try to pattern match a multisig bool isMultiSig( int &_m, int &_n, std::vector &addresses, const uint8_t *p, size_t scriptSize ) { auto e = scriptSize + p; if(scriptSize<=5) { return false; } auto m = (*(p++) - 0x50); // OP_1 ... OP-16 auto isMValid = (1<=m && m<=16); if(!isMValid) { return false; } int count = 0; while(1) { uint64_t dataSize = 0; auto ok = getOpPushData(p, dataSize); if(e<=p) { return false; } if(!ok) { break; } uint160_t addr; auto sz = sizeof(addr); memcpy(addr.v, p-sz, sz); addresses.push_back(addr); ++count; } auto n = (*(p++) - 0x50); // OP_1 ... OP-16 auto isNValid = (1<=n && n<=16); if(!isNValid || n!=count) { return false; } auto lastOp = *(p++); bool ok = (0xAE==lastOp) && // OP_CHECKMULTISIG (m<=n) && (p==e); if(ok) { _m = m; _n = n; } return ok; } void showScript( const uint8_t *p, size_t scriptSize, const char *header, const char *indent, bool showAscii ) { bool first = true; const uint8_t *e = scriptSize + p; indent = indent ? indent : ""; while(likely(p addresses; if( isMultiSig( m, n, addresses, script, scriptSize ) ) { packMultiSig(pubKeyHash, addresses, m, n); addrType[0] = 8; return 4; } // Broken output scripts that were created by p2pool for a while if( 0x73==script[0] && // OP_IFDUP 0x63==script[1] && // OP_IF 0x72==script[2] && // OP_2SWAP 0x69==script[3] && // OP_VERIFY 0x70==script[4] && // OP_2OVER 0x74==script[5] // OP_DEPTH ) { return -2; } // A non-functional "comment" script if(isCommentScript(script, scriptSize)) { return -3; } // A challenge: anyone who can find X such that 0==RIPEMD160(X) stands to earn a bunch of coins if( 0x76==script[0] && // OP_DUP 0xA9==script[1] && // OP_HASH160 0x00==script[2] && // OP_0 0x88==script[3] && // OP_EQUALVERIFY 0xAC==script[4] // OP_CHECKSIG ) { return -4; } #if 0 // TODO : some scripts are solved by satoshi's client and not by the above. track them // Unknown output script type -- very likely lost coins, but hit the satoshi script solver to make sure int result = extractAddress(pubKeyHash, script, scriptSize); if(result) return -1; return 5; printf("EXOTIC OUTPUT SCRIPT:\n"); showScript(script, scriptSize); #endif // Something we didn't understand return -1; } const uint8_t *loadKeyHash( const uint8_t *hexHash ) { static bool loaded = false; static uint8_t hash[kRIPEMD160ByteSize]; const char *someHexHash = "0568015a9facccfd09d70d409b6fc1a5546cecc6"; // 1VayNert3x1KzbpzMGt2qdqrAThiRovi8 deepbit's very large address if(unlikely(!loaded)) { if(0==hexHash) hexHash = reinterpret_cast(someHexHash); if((2*kRIPEMD160ByteSize)!=strlen((const char *)hexHash)) errFatal("specified hash has wrong length"); fromHex(hash, hexHash, sizeof(hash), false); loaded = true; } return hash; } uint8_t fromB58Digit( uint8_t digit, bool abortOnErr ) { if('1'<=digit && digit<='9') return (digit - '1') + 0; if('A'<=digit && digit<='H') return (digit - 'A') + 9; if('J'<=digit && digit<='N') return (digit - 'J') + 17; if('P'<=digit && digit<='Z') return (digit - 'P') + 22; if('a'<=digit && digit<='k') return (digit - 'a') + 33; if('m'<=digit && digit<='z') return (digit - 'm') + 44; if(abortOnErr) errFatal("incorrect base58 digit %c", digit); return 0xff; } static int getCoinType() { return #if defined(PROTOSHARES) 56 #endif #if defined(DARKCOIN) 48 + 28 #endif #if defined(PAYCON) 55 #endif #if defined(LITECOIN) 48 #endif #if defined(BITCOIN) 0 #endif #if defined(TESTNET3) 0 #endif #if defined(FEDORACOIN) 33 #endif #if defined(PEERCOIN) 48 + 7 #endif #if defined(CLAM) 137 #endif #if defined(JUMBUCKS) 43 #endif #if defined(DOGECOIN) 30 #endif #if defined(MYRIADCOIN) 50 #endif #if defined(UNOBTANIUM) 130 #endif ; } bool addrToHash160( uint8_t *hash160, const uint8_t *addr, bool checkHash, bool verbose ) { static BIGNUM *sum = 0; static BN_CTX *ctx = 0; if(unlikely(!ctx)) { ctx = BN_CTX_new(); BN_CTX_init(ctx); sum = BN_new(); } BN_zero(sum); while(1) { uint8_t c = *(addr++); if(unlikely(0==c)) break; uint8_t dg = fromB58Digit(c); BN_mul_word(sum, 58); BN_add_word(sum, dg); } uint8_t buf[4 + 2 + kRIPEMD160ByteSize + 4]; size_t size = BN_bn2mpi(sum, 0); if(sizeof(buf)>24) & 0xff; buf[ 1] = (size>>16) & 0xff; buf[ 2] = (size>> 8) & 0xff; buf[ 3] = (size>> 0) & 0xff; buf[ 4] = 0; buf[ 5] = getCoinType() + type; sha256Twice( 4 + 2 + kRIPEMD160ByteSize + buf, 4 + 1 + buf, 1 + kRIPEMD160ByteSize ); static BIGNUM *b58 = 0; static BIGNUM *num = 0; static BIGNUM *div = 0; static BIGNUM *rem = 0; static BN_CTX *ctx = 0; if(!ctx) { ctx = BN_CTX_new(); BN_CTX_init(ctx); b58 = BN_new(); num = BN_new(); div = BN_new(); rem = BN_new(); BN_set_word(b58, 58); } BN_mpi2bn(buf, 4+size, num); uint8_t *p = addr; while(!BN_is_zero(num)) { int r = BN_div(div, rem, num, b58, ctx); if(!r) errFatal("BN_div failed"); BN_copy(num, div); uint32_t digit = BN_get_word(rem); *(p++) = b58Digits[digit]; } const uint8_t *a = (5+buf); const uint8_t *e = 1 + kRIPEMD160ByteSize + (5+buf); while(a &result, const uint8_t *buf, bool verbose ) { uint160_t h160; bool ok = guessHash160(h160.v, buf, verbose); if(ok) result.push_back(h160); return ok; } void loadKeyList( std::vector &result, const char *str, bool verbose ) { bool isFile = ( 'f'==str[0] && 'i'==str[1] && 'l'==str[2] && 'e'==str[3] && ':'==str[4] ); if(!isFile) { addAddr(result, (uint8_t*)str, true); return; } const char *fileName = 5+str; bool isStdIn = ('-'==fileName[0] && 0==fileName[1]); FILE *f = isStdIn ? stdin : fopen(fileName, "r"); if(!f) { warning("couldn't open %s for reading\n", fileName); return; } size_t found = 0; size_t lineCount = 0; double start = Timer::usecs(); while(1) { char buf[1024]; char *r = fgets(buf, sizeof(buf), f); if(r==0) break; ++lineCount; size_t sz = strlen(buf); if('\n'==buf[sz-1]) buf[sz-1] = 0; uint160_t h160; bool ok = addAddr(result, (uint8_t*)buf, verbose); if(ok) { ++found; } else { if(verbose) { warning( "in file %s, line %d, %s is not an address\n", fileName, lineCount, buf ); } } } fclose(f); double elapsed = (Timer::usecs() - start)*1e-6; info( "file %s loaded in %.2f secs, found %d addresses", fileName, elapsed, (int)found ); } void loadHash256List( std::vector &result, const char *str, bool verbose ) { bool isFile = ( 'f'==str[0] && 'i'==str[1] && 'l'==str[2] && 'e'==str[3] && ':'==str[4] ); if(!isFile) { size_t sz = strlen(str); if(2*kSHA256ByteSize!=sz) errFatal("%s is not a valid TX hash", str); uint256_t h256; fromHex(h256.v, (const uint8_t *)str); result.push_back(h256); return; } const char *fileName = 5+str; bool isStdIn = ('-'==fileName[0] && 0==fileName[1]); FILE *f = isStdIn ? stdin : fopen(fileName, "r"); if(!f) { warning("couldn't open %s for reading\n", fileName); return; } size_t lineCount = 0; while(1) { char buf[1024]; char *r = fgets(buf, sizeof(buf), f); if(r==0) break; ++lineCount; size_t sz = strlen(buf); if(2*kSHA256ByteSize<=sz) { uint256_t h256; bool ok = fromHex(h256.v, (const uint8_t *)buf, kSHA256ByteSize, true, false); if(ok) result.push_back(h256); else if(verbose) { warning( "in file %s, line %d, %s is not a valid TX hash\n", fileName, lineCount, buf ); } } } fclose(f); } std::string pr128( const uint128_t &y ) { static char result[1024]; char *p = 1023+result; *(p--) = 0; auto x = y; while(1) { *(p--) = (char)((x % 10) + '0'); if(unlikely(0==x)) break; x /= 10; } ++p; return std::string(p[0]!='0' ? p : (1022+result==p) ? p : p+1); } void showFullAddr( const Hash160 &addr, bool both ) { uint8_t b58[128]; if(both) { showHex(addr, sizeof(uint160_t), false); } hash160ToAddr(b58, addr); printf( "%s%s", both ? " " : "", b58 ); } uint64_t getBaseReward( uint64_t h ) { static const uint64_t kCoin = 100000000; uint64_t reward = (50 * kCoin); uint64_t shift = (h/210000); reward >>= shift; return reward; } const char *getInterestingAddr() { const char *addr = #if defined(BITCOIN) "1dice8EMZmqKvrGE4Qc9bUFf9PX3xaYDp" #elif defined(TESTNET3) "mxRN6AQJaDi5R6KmvMaEmZGe3n5ScV9u33" #elif defined(LITECOIN) "LKvTVnkK2rAkJXfgPdkaDRgvEGvazxWS9o" #elif defined(DARKCOIN) "XnuCAYmAiVHE6Xv3D7Xw685wWzqtcfexLh" #elif defined(PEERCOIN) "PDH9AeruMUGh2JzYYTpaNtjLAcfGV5LEto" #elif defined(CLAM) "xQKq1LwJQQkg1A5cmB9znGozCKLkAaKJHW" #elif defined(PAYCON) "PShpEEfcy8UrBPWoefsNnq8oz6bX7dNxnP" #elif defined(JUMBUCKS) "JhbrvAmM7kNpwA6wD5KoAsbtikLWWMNPcM" #elif defined(MYRIADCOIN) "MDiceoNDTQboRxYKMTstxxRBY493Lg9bV2" #elif defined(UNOBTANIUM) "udicetdXSo6Zc7vhWgAZfz4XrwagAX34RK" #else fatal("no address specified") #endif ; warning("no addresses specified, using popular address %s", addr); return addr; } #if defined(DARKCOIN) #include void h9( uint8_t *h9r, const uint8_t *buf, uint64_t size ) { uint256 hash = Hash9(buf, size + buf); memcpy(h9r, &hash, sizeof(hash)); } #endif #if defined(PAYCON) #include void h13( uint8_t *h9r, const uint8_t *buf, uint64_t size ) { uint256 hash = Hash13(buf, size + buf); memcpy(h9r, &hash, sizeof(hash)); } #endif #if defined(CLAM) || defined(JUMBUCKS) #include void scrypt( uint8_t *scr, const uint8_t *buf, uint64_t size ) { unsigned char scratchpad[SCRYPT_BUFFER_SIZE]; uint256 hash = scrypt_nosalt(buf, size, scratchpad); memcpy(scr, &hash, sizeof(hash)); } #endif void canonicalHexDump( const uint8_t *p, size_t size, const char *indent ) { const uint8_t *s = p; const uint8_t *e = size + p; while(p