Python bitcoin miner not letting me define variable after mine - python-3.x

I have been trying to create a python bitcoin miner, that ACTUALLY puts the coins somewhere, so thats the first part of my quesiton, and the second part is how do I fix this error?
This is all of my code:
import hashlib
import time
max_nonce = 2 ** 32 # 4 billion
def proof_of_work(header, difficulty_bits):
# calculate the difficulty target
target = 2 ** (256-difficulty_bits)
for nonce in range(max_nonce):
hash_result = hashlib.sha256(str(header)+str(nonce)).hexdigest()
# check if this is a valid result, below the target
if int(hash_result, 16) < target:
print ("Success with nonce %d" % nonce)
print ("Hash is %s" % hash_result)
return (hash_result,nonce)
print ("Failed after %d (max_nonce) tries" % nonce)
return nonce
if __name__ == '__main__':
nonce = 0
hash_result = ''
# difficulty from 0 to 31 bits
for difficulty_bits in range(32):
difficulty = 2 ** difficulty_bits
print ("Difficulty: %ld (%d bits)" % (difficulty, difficulty_bits))
print ("Starting search...")
# checkpoint the current time
start_time = time.time()
# make a new block which includes the hash from the previous block
# we fake a block of transactions - just a string
new_block = 'test block with transactions' + hash_result
# find a valid nonce for the new block
(hash_result, nonce) = proof_of_work((new_block, difficulty_bits).hexdigest()
# checkpoint how long it took to find a result
end_time = time.time()
The line above this, The end_time seems to get an error, with no definition to what the error is. Please help.
Please note that I have tried a great deal of commenting out a bunch of things, changing code, and this is in python 3

I'm writing this as an answer because of the many issues.
First, hashllib requires byte strings. You would need
hash_result = hashlib.sha256((header+str(nonce)).encode('utf-8')).hexdigest()
Second, you're doing proof_of_work(...).hexdigest(), but that function isn't returning a hash object. You are already calling hexdigest. Your function either returns a 2-tuple, or a nonce. You want to remove the hexdigest call:
# find a valid nonce for the new block
(hash_result, nonce) = proof_of_work((new_block, difficulty_bits)
And, in the final line of proof_of_work change
return nonce
to
return (None, nonce)
Next, you are converting the nonce to decimal digits to tack it on to the block. That is completely wrong. The nonce needs to be a 4-byte value. Something like:
enonce = struct.pack('I', nonce)
hash_result = hashlib.sha256(header.encode('utf-8')+enonce).hexdigest()
Finally, this whole thing is silly. Have you timed that inner loop to see how long it takes? On my box, it takes about 500 microseconds per loop. To run that 4 billion times would require a month and a half. To repeat that for all 32 difficult values would make it take 4 years.

Related

Passwords Generator, problem writing it to a file

i was doing a password generator. And i wanted to write all the passwords to a file. But it only write one line, even though i used the method .writelines().
Python File:
import random
lower = "abcdefghijkmnopqrstuvwxyz"
upper = "ABCDEFGHIJKMNOPQRSTUVWXYZ"
num = "0123456789"
lenght = 24
all = lower+upper+num
pwd = "".join(random.sample(all,lenght))
for i in range(0,100):
with open("pwd.txt","w+") as f:
f.writelines(pwd)
pwd.txt:
WQaTfK4R3crgZV5XE16Yyoik
To generate 100 different passwords and add them to the file pwd.txt, I made a few changes to your code. I put the variable pwd inside your for loop, to generate 100 different passwords. Then, to avoid redefining the variable f 100 times, I put that before the for loop. Also, when writing to the file, I included a newline, so that each password would be written to a new line. Here is the resulting code I produced. Tell me if you need anything else.
import random
lower = "abcdefghijkmnopqrstuvwxyz"
upper = "ABCDEFGHIJKMNOPQRSTUVWXYZ"
num = "0123456789"
length = 24
all = lower+upper+num
with open("pwd.txt", "w+") as f:
for i in range(0, 100):
pwd = "".join(random.sample(all, length))
f.write(pwd + "\n")
f.close()
If you were trying to rewrite the same password 100 times to the file pwd.txt, my answer needs some editing. I wasn't sure if that was actually what you wanted. If that case, here would be the edited code:
import random
lower = "abcdefghijkmnopqrstuvwxyz"
upper = "ABCDEFGHIJKMNOPQRSTUVWXYZ"
num = "0123456789"
length = 24
all = lower+upper+num
pwd = "".join(random.sample(all, length))
with open("pwd.txt", "w+") as f:
for i in range(0, 100):
f.write(pwd + "\n")
f.close()
I'd advise you to use string module to get the ascii letters and numbers, using string.ascii_letters and string.digits.
This way you'd get a function get_pass, like so:
import string
import random
def get_pass(length):
return ''.join(random.sample(string.ascii_letters + string.digits, length))
Then, as you're not actually writing a ton of data, but a small set, you can use a list comprehension and use writelines() over it, just two lines of code.
Be careful, as this pre-loads all the passwords in memory before writing the file, so if you use it for a huge number of passwords it'll lead to memory usage issues.
with open('pwd.txt', 'w') as fop:
fop.writelines([f'{p}\n' for p in (get_pass(24) for _ in range(100))])
And you'll end up with a file like:
uDBN1Xr7bF6TJa4dsypZw8lC
xLeOJQZWpC1h42RI6BSnq0zK
LqzuhVoCEi1BWJvSd0DOcAMQ
wUyurf150BldE3ibCJMSa8jP
BmGI0qobunfk59PVxMYazAip
qozsIwCH3rmgBRyDQJ5W7APE
QAPe0fwkj4RmagTd6ctzMsYy
wAZ9Q8WLvI7deDgSa4YryslB
mM8seBJWiTAxh5nqKbLkj1vU
SB8JeA45H10UD9u7k6zjKvyc
7GnWQ5SvNgADclRB42tqUmhZ
... up until 100 lines

Beginner in Python - Password Generator with Condtionals not breaking while loop

I created a random password generator. With this generator is pulls from a variable of upper/lower case letters, numbers, and symbols and generates a random password.
The issue I'm having is I want to have a condition of 8 or more characters and if you don't request a long enough password it pops a message stating that it has to be at least 8 characters. The original creation of the generator would stop the code there and you would have to start all over. What I'm trying to do is use a while loop to ask the length again.
The issue I have come across is that my code is stuck in an infinite loop and will not break. When I do add a break I either get an error saying its out of a function or it just stops the code on input.
import random
chars ="AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890!##$%^&*"
length = input('How long would you like the password? ')
length = int(length)
if length < 8:
print('Password must be at least 8 characters')
while True:
length = input('How long would you like your password?')
length = int(length)
break
if length >= 8:
num = input('How many passwords do you want?')
num = int(num)
for p in range(number_of_pass):
password = 'Your password is: '
for c in range(length):
password += random.choice(chars)
print(password)

I am getting a "Time Limit Exceeded " error in the following code. How to fix that error

The following code is my view of checking whether the sum of a number and it's reverse is a palindrome or not.If the sum is a palindrome then sum will be displayed.Otherwise the process will be repeated until we get a palindrome. When it is set to execute, I am getting a time limit exceeded error.Where do I need to correct the code?
def pal(n1):
temp=n1
rev=0
while(temp>0):
rev=(rev*10)+(temp%10)
temp=temp/10
sum1=n1+rev
temp=sum1
rev=0
while(temp>0):
rev=(rev*10)+(temp%10)
temp=temp/10
if(rev==sum1):
print(sum1)
else:
pal(sum1)
n=int(input())
pal(n)
I expect the output of a number 453 to be 6666.
i.e.
453+354=807 (not a palindrome. So repeat the process)
807+708=1515
1515+5151=6666 (it is a palindrome)
Your problem is that you are checking for while temp > 0: but inside that loop you are using float division: temp=temp/10. So the condition will always hold. For example:
>>> 8/10
0.8
>>> 0.8/10
0.08
What you want is to change your divisions to int division:
>>> 8//10
0
Still you might consider working with strings which is much easier in that case:
def pal(n):
rev_n = str(n)[::-1]
sum_str = str(n + int(rev_n))
while sum_str != sum_str[::-1]:
# print(sum_str)
sum_rev = sum_str[::-1]
sum_str = str(int(sum_str) + int(sum_rev))
print(sum_str)
And with the commented print this gives:
>>> pal(453)
807
1515
6666
Here is one way of doing this using string manipulation, which goes a lot easier than trying to do this with numbers. It is also a more direct translation of what you describe afterwards. (I do not really see the link between your code and your description...)
def is_palindrome(text):
# : approach1, faster for large inputs
# mid_length = len(text) // 2
# offset = 0 if len(text) % 2 else 1
# return text[:mid_length] == text[:-mid_length - offset:-1]
# : approach2, faster for small inputs
return text == text[::-1]
def palindrome_sum(num):
while not is_palindrome(num):
num = str(int(num) + int(num[::-1]))
return num
num = input() # 453
palindrome = palindrome_sum(num)
print(palindrome)
# 6666

String index out of range and I can't fix the error

So below is my code. Somewhere in the "for digit in observed" loop there is an indexing error that I can't seem to find or fix. I believe it's something to do with the PINS list, but I'm not sure, as none of my edits have made a difference. Test case that fails is observed = '11'. Single cases all pass. Unfortunately as I'm using codewars, there is no line given for the error, just the following:
Traceback:
in
in get_pins
IndexError: string index out of range
def get_pins(observed):
# Let's see what we're working with
print("observed")
print(observed)
print(" ")
# Dictionary of possible numbers for a half-assed observation of a key press.
possible = {'0':'08','1':'124','2':'1235','3':'236',
'4':'1457','5':'24568','6':'3569',
'7':'478','8':'05789','9':'689'}
# Single digit pwd case
PINS=[]
if len(observed) == 1:
for digit in possible[observed]:
PINS.append(digit)
return PINS
# Find number of possible PINs
num_possibles = 1
# Step through observed digits
for digit in observed:
num_possibles*=len(possible[digit])
# Populate PINS to allow string manipulation
PINS = " "*num_possibles
print(PINS[num_possibles])
num_change = num_possibles
change = []
count = 0
# Step through observed, determine change of digit,
for digit in observed:
# Last digit in observed means it iterates every time
if digit != observed[len(observed)-1]:
# Develop array for checking position
num_change = num_change/len(possible[digit])
for i in range(1,len(possible[digit])):
change.append(i*num_change)
print(change)
# Populate PINS with possible digit, full pin is created after final iteration of digit/observed loop
for pin in range(0,num_possibles-1):
PINS[pin] = PINS[pin] + possible[digit][count]
if (pin+1) in change:
count+=1
change=[]
count =0
else:
for pin in range(0,num_possibles-1):
PINS[pin] = PINS[pin] + possible[digit][count]
count+=1
if count == len(possible[digit]):
count = 0
return PINS
The problem is here:
PINS = " "*num_possibles
print(PINS[num_possibles])
The first line creates a string of spaces of length num_possibles. This means that the valid indices are 0, 1, ..., num_possibles - 1. However, in the very next line you try to index the string at the non-existent index num_possibles.
I would simply drop that print. What is the point of it? You know that PINS is a string of all spaces, so why bother?
Strings are immutable, since PINS is a string, the line
PINS[pin] = PINS[pin] + possible[digit][count]
would trigger the error:
TypeError: 'str' object does not support item assignment
What you should do is to initialize PINS as
PINS = [' ']*num_possibles
Or, probably even better
PINS = ['']*num_possibles
In which case
PINS[pin] = PINS[pin] + possible[digit][count]
would be legal (although it could be shortened by use of +=) -- although I'm not sure if this is what you really want to do since you are concatenating the strings stored as values in the possible and not adding the numbers represented by those strings.
At the end of the function, replace return PINS by return''.join(PINS)`
That will fix some of your bugs, but since I know neither intended input nor intended output I can't say any more.

How can I create a simple python brute force function?

I am trying to create a function that will use brute force for an academic python project. The password can be limited I want to pass in the password and the function iterate through a set of characters(a-z,A-Z,0-9) trying combinations till the password is found. I know this will be inefficient so for testing lets assume the password is 4 characters long. Any help getting started on writing this function would be appreciated.
gen = itertools.combinations_with_replacement(characters,password_length) #1
for password in gen: #2
check_password(password) #3
here's how it works:
line 1: this creates a generator. it's like a function that remembers where it left off. Check this out for more info: http://getpython3.com/diveintopython3/generators.html. This particular generator goes through all possible combinations of the given characters of the given length.
line 2: for each iteration of the for loop next(gen) is called. This yields the next value
line 3: Do what you need to do
for example if characters = '01234567890' and password_length = 2 then the loop will run through the combinations: ('0','0'), ('0','1'), ('0','2')...('0','9'),('1','0'),('1','1')...('9','9').
For a pre-known length :
import random
a_z = "abcdefghijklmnopqrstuvwxyz_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
while password != curtry:
currenttry = random.choice(a_z)+random.choice(a_z)+random.choice(a_z)+random.choice(a_z)
For a random length :
import random
a_z = "abcdefghijklmnopqrstuvwxyz_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
while password != curtry:
leng = random.randint(4,12) #random int between 4 and 12
i = 0
curtry = "lol"
for i<leng:
curtry += random.choice(a_z)

Resources