Vanity TXID mining algo which uses txn malleability (Python multiprocessing + multithreading)
Ever seen a TXID or token ID with '000000' out the front? I've created a couple examples of SLP tokens with vanity IDs.
https://simpleledger.info/token/0000003449671e4aef02f6cca1c2df729f110fb1347123ad4450c42691a153f6
https://simpleledger.info/token/abcdef0490cc19314c47863cce2475365acca6188733d7e2bf1ebb653c4c0dff
The txns can also be seen in the address history. I think the TXIDs look cute with 0s out the front, but it's less private because any repeated patterns could be used to trace people or exchanges. It's interesting to time how long vanity hashes take to generate, but Python may be slow. A token or NFT could demonstrate PoW in its own ID. An exchange could put their own pattern out the front of all withdrawals, etc. Users of EC might like to see how long each '0' takes.
I've included an example below, with the full Python script. It can be copy-pasted and should run fine. I'd like to develop an Electron Cash (+ SLP edition) plugin which allows people to create their own (secure) P2SH address (starts with a 'p') which enables txn malleability. It's gonna take some time! Technically a smart contract is needed which allows a nonce in the sigscript. Python code should work on all supported platforms.
Update: CTOR put my '000000' examples in 2nd place, just after coinbase. e.g. blocks 706165 & 706255.
# Enter the desired starting pattern, at least length 1. Hex digits only (0-9 & a-f). Short patterns result in simultaneous console outputs due to lag in multi-process termination (user can set 1 thread & processor). Length 6 seems to usually take 5-30 secs. Pattern = '000000' # Copy-paste the raw TX, which is ready to be broadcast, below. Then this script is ready to be executed, as long as first input is from a P2SH address which supports this sort of txn malleability. I've only tested the BCH network, not BTC. SLP token creation & transfers work. TX=\ '010000000185290eb8e9e2fdb3caa15310c9acafa9ad357792beac901bdedfee8e6d000000020000001a0018144956cd5ed8e4fd0c75c6344e691c5ea1c11f8cb7517777feffffff015c0f0000000000001976a9144956cd5ed8e4fd0c75c6344e691c5ea1c11f8cb788accdc60a00' # This example was from an insecure address, see www.blockchain.com/bch/tx/000000c8eda75f5656201fc0b2436fb3e20e3d1474566cc80571250151a13015 # The following 3 options don't need to be changed. NonceSizeInit=1 # Initial nonce size, in Bytes. Must be a +ve int. A successful nonce should have similar length to Pattern, and it can be made bigger if first attempt is unsuccessful. Threads=8 # Threads per processor. I've only tested powers of 2 & 1. 8 is faster than 1. 8 & 8 give 64 threads total. More than 256 threads total would require NonceSizeInit>1 Processors=0 # How many cores? 0 defaults to max (100% CPU). I've only tested powers of 2, 1 & 0. PatternLen=len(Pattern) PatternEven=bool(1-PatternLen%2) Pattern2=''.join(reversed([Pattern[i:i+2] for i in range(0, PatternLen, 2)])) # Reverse Pattern outside Nonce loop. SigScriptSize=int(TX[82:84],16) NoncePos=43 # Byte starting position of Nonce. from hashlib import sha256 import threading import multiprocessing if Processors==0: Processors=multiprocessing.cpu_count() class Hasher(threading.Thread): def __init__(self,Processor,Thread,Event): super(Hasher,self).__init__() self.Processor=Processor self.Thread=Thread self.Event=Event def run(self): NonceSize=NonceSizeInit NoncePos2=NoncePos+NonceSize # End Byte of Nonce. SigScriptSize2=SigScriptSize+NonceSize # Malleated sigscript size. while True: TX2=TX[:82]+SigScriptSize2.to_bytes(1,'big').hex()+NonceSize.to_bytes(1,'big').hex()+TX[86:NoncePos*2]+"00"*NonceSize+TX[NoncePos*2:] # SigScriptSize2 must be in final result, and I assume it's less than 256. TX2=bytearray.fromhex(TX2) NonceTotal=256**NonceSize Nonces=int(NonceTotal/(Processors*Threads)) # Nonces/Thread NoncesStart=self.Processor*int(NonceTotal/Processors)+self.Thread*Nonces if PatternEven: # Separating even from odd PatternLen should make a faster Nonce loop. for Nonce in range(NoncesStart,NoncesStart+Nonces): # I tested a 'while' loop but 'for' was faster. TX2[NoncePos:NoncePos2]=Nonce.to_bytes(NonceSize,'big') TXID2=sha256(sha256(TX2).digest()).hexdigest() Finished= TXID2[-PatternLen:]==Pattern2 if Finished: break elif PatternLen==1: for Nonce in range(NoncesStart,NoncesStart+Nonces): TX2[NoncePos:NoncePos2]=Nonce.to_bytes(NonceSize,'big') TXID2=sha256(sha256(TX2).digest()).hexdigest() Finished= TXID2[-2]==Pattern2[0] if Finished: break else: for Nonce in range(NoncesStart,NoncesStart+Nonces): TX2[NoncePos:NoncePos2]=Nonce.to_bytes(NonceSize,'big') TXID2=sha256(sha256(TX2).digest()).hexdigest() Finished=(TXID2[1-PatternLen:]==Pattern2[1:]) & (TXID2[-PatternLen-1]==Pattern2[0]) if Finished: break if Finished: break NonceSize+=1 NoncePos2+=1 SigScriptSize2+=1 print(TX2.hex()) print('Broadcast the above raw TX.') TXID2=''.join(reversed([TXID2[i:i+2] for i in range(0, len(TXID2), 2)])) print(TXID2+' is the TXID') print(Pattern+' is the pattern.') print(Nonce.to_bytes(NonceSize,'big').hex()+' is the nonce which lengthens the raw TX by malleating the first sigscript.') self.Event.set() def Process(Processor,Event): for Thread in range(Threads): Hasher(Processor,Thread,Event).start() if __name__ == '__main__': Event=multiprocessing.Event() for Processor in range(Processors): multiprocessing.Process(target=Process,args=(Processor,Event)).start() Event.wait() for Process in multiprocessing.active_children(): Process.terminate() # This is the slowest, but simplest, way to end the script. :( [link] [comments]