It was the Bitcointalk forum that inspired us to create Bitcointalksearch.org - Bitcointalk is an excellent site that should be the default page for anybody dealing in cryptocurrency, since it is a virtual gold-mine of data. However, our experience and user feedback led us create our site; Bitcointalk's search is slow, and difficult to get the results you need, because you need to log in first to find anything useful - furthermore, there are rate limiters for their search functionality.
The aim of our project is to create a faster website that yields more results and faster without having to create an account and eliminate the need to log in - your personal data, therefore, will never be in jeopardy since we are not asking for any of your data and you don't need to provide them to use our site with all of its capabilities.
We created this website with the sole purpose of users being able to search quickly and efficiently in the field of cryptocurrency so they will have access to the latest and most accurate information and thereby assisting the crypto-community at large.
#!/usr/bin/env python
"""
# Special thanks to Gavin Andresen from bitcointalk.org
# in reference to: https://bitcointalk.org/index.php?topic=1026.0
# Edited By/Author Josh Lee PyTis.com, I also release my changes into the
# public domain.
"""
class BTCaddress(str):
""" Custom Bitcoin Address Verify-turend into a type for type-casting.
"""
import re
address_pattern = "[a-zA-Z1-9]{27,35}$"
address_expr = re.compile(r"%s"%address_pattern)
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)
_valid = False
_version = None
def __new__(cls,val):
if val is None:
# allow None to be passed in, so that we may clear out bitcoin addresses
# if you want, youc an raise an error instead, so that None doesn't pass silently
inst = str.__new__(cls, None)
inst._valid = False
inst._version = None
return inst
# I don't know if there could be a valid address with only numbers, but just in-case
if isinstance(val, int): val = str(val)
# remove preceading and trailing whitespace
if isinstance(val, basestring):
val = val.strip()
if not val:
# again, allow '' to be passed in, so that we may clear out bitcoin addresses
# if you want, you can raise an error instead, so that None doesn't pass silently
inst = str.__new__(cls, None)
inst._valid = False
inst._version = None
return inst
else:
if not cls.address_expr.match(val):
raise ValueError('Invalid Bitcoin address. Bad RE match r"%s".' % cls.address_pattern)
version = cls.getVersion(val)
if version is None:
raise ValueError('Invalid Bitcoin address. Version Missmatch: %r' % version)
else:
inst = str.__new__(cls, val)
inst._valid = True
inst._version = version
return inst
else:
raise TypeError('Invalid Bitcoin address. Not a string.')
valid = property(lambda s: s._valid)
version = property(lambda s: s._version)
@classmethod
def getVersion(cls, strAddress):
""" Returns None if strAddress is invalid. Otherwise returns integer version of address. """
from Crypto.Hash import SHA256
addr = cls.b58decode(strAddress,25)
if addr is None: return None
version = addr[0]
checksum = addr[-4:]
vh160 = addr[:-4] # Version plus hash160 is what is checksummed
h3=SHA256.new(SHA256.new(vh160).digest()).digest()
if h3[0:4] == checksum:
return ord(version)
return None
@classmethod
def b58encode(cls, v):
""" encode v, which is a string of bytes, to base58.
"""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += (256**i) * ord(c)
result = ''
while long_value >= cls.__b58base:
div, mod = divmod(long_value, cls.__b58base)
result = cls.__b58chars[mod] + result
long_value = div
result = cls.__b58chars[long_value] + result
# Bitcoin does a little leading-zero-compression:
# leading 0-bytes in the input become leading-1s
nPad = 0
for c in v:
if c == '\0': nPad += 1
else: break
return (cls.__b58chars[0]*nPad) + result
@classmethod
def b58decode(cls, v, length):
""" decode v into a string of len bytes
"""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += cls.__b58chars.find(c) * (cls.__b58base**i)
result = ''
while long_value >= 256:
div, mod = divmod(long_value, 256)
result = chr(mod) + result
long_value = div
result = chr(long_value) + result
nPad = 0
for c in v:
if c == cls.__b58chars[0]: nPad += 1
else: break
result = chr(0)*nPad + result
if length is not None and len(result) != length:
return None
return result
# - - - - - - - - - - - - - -
# END OF Custom Type class.
#
#
# tests below
# I found a page on a bitcoin wiki to explain to me different bitcoin address
# versions, I decided to test these, and other things that could go wrong.
# I then altered my code above, to get desired results.
#
# For more information on bitcoin address versions, please follow link:
# https://en.bitcoin.it/wiki/List_of_address_prefixes
tests = [
'17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem', # version 0 || TEST 1
u'3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX', # version 5 || TEST 2
'LhK2kQwiaAvhjWY799cZvMyYwnQAcxkarr', # vesrion 48 || TEST 3
'NATX6zEUNfxfvgVwz8qVnnw3hLhhYXhgQn', # version 52 || TEST 4
'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn', # version 111 || TEST 5
'5Hwgr3u458GLafKBgxtssHSPqJnYoGrSzgQsPwLFhLNYskDPyyA', # version 128 || TEST 6
'92Pg46rUhgTT7romnV7iGW6W1gbGdeezqdbJCzShkCsYNzyyNcc', # version 239 || TEST 7
None, # testing None, No version || TEST 8
' 1111111111111111111114oLvT2', # test from https://bitcointalk.org/index.php?topic=1026.0 || TEST 9
float(123456789.01), #|| TEST 10
bool(True), # || TEST 11
'', # || TEST 12
'1NnZEPLmBEK2HryY4heeJQhQPB8LLbNiPe' # my bitcoin address :-) || TEST 13
]
for i, test in enumerate(tests):
print '-'*80
print 'typeof test: ', type(test)
print 'original value: ', test
try:
t = BTCaddress(test)
except TypeError, e:
print "TypeError: %s" % str(e)
except ValueError, e:
print "ValueError: %s" % str(e)
else:
print 'test %s' % i, t
print 'test %s.type' % i, type(t)
print 'test %s.valid' % i, t.valid
print 'test %s.version' % i, t.version
print 't.getVersion()', t.getVersion(str(t))
server:~$ bitcoind validateaddress mkZuF2onXAxyGuuvoALbPEesMg99uv6k7r
{
"isvalid" : true,
"address" : "mkZuF2onXAxyGuuvoALbPEesMg99uv6k7r",
"ismine" : false
}
server:~$ bitcoind validateaddress mkZuF2onXAxyGuuvoALbPEeIMg99uv6k7r
{
"isvalid" : false
}
server:~$ bitcoind validateaddress 7kZuF2onXAxyGuuvoALbPEeIMg99uv6k7r
{
"isvalid" : false
}
def validate_address(self, address):
"""
Does simple validation of a bitcoin-like address.
Source: http://bit.ly/17OhFP5
param : address : an ASCII or unicode string, of a bitcoin address.
returns : boolean, indicating that the address has a correct format.
"""
address = self.clean(address)
# The first character indicates the "version" of the address.
CHARS_OK_FIRST = "123"
# alphanumeric characters without : l I O 0
CHARS_OK = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
# We do not check the high length limit of the address.
# Usually, it is 35, but nobody knows what could happen in the future.
if len(address) < 27:
return False
elif address[0] not in CHARS_OK_FIRST:
return False
# We use the function "all" by passing it an enumerator as parameter.
# It does a little optimization :
# if one of the character is not valid, the next ones are not tested.
return all( ( char in CHARS_OK for char in address[1:] ) )
address is valid
";address is NOT valid
";