├── README.md ├── aula-3.py ├── aula-4.py ├── aula-5.py ├── aula-6.py └── aula-7.py /README.md: -------------------------------------------------------------------------------- 1 | # Curso: Criando uma criptomoeda do ZERO com Python 2 | Repositório com os códigos do curso 3 | -------------------------------------------------------------------------------- /aula-3.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import time 3 | import binascii 4 | 5 | class Block: 6 | def __init__(self, index, previousHash, timestamp, data, hash, difficulty, nonce): 7 | self.index = index 8 | self.previousHash = previousHash 9 | self.timestamp = timestamp 10 | self.data = data 11 | self.hash = hash 12 | self.difficulty = difficulty 13 | self.nonce = nonce 14 | 15 | 16 | class Blockchain: 17 | def __init__(self, genesisBlock): 18 | self.__chain = [] 19 | self.__chain.append(genesisBlock) 20 | 21 | def getLatestBlock(self): 22 | return self.__chain[len(self.__chain) - 1] 23 | 24 | def generateNextBlock(self, data): 25 | previousBlock = self.getLatestBlock() 26 | nextIndex = previousBlock.index + 1 27 | nextTimestamp = int(round(time.time() * 1000)) 28 | nextPreviousHash = previousBlock.hash 29 | newBlock = Block(nextIndex, nextPreviousHash, nextTimestamp, data, 30 | calculateHash(nextIndex, nextPreviousHash, nextTimestamp, data)) 31 | if self.validatingBlock(newBlock): 32 | self.__chain.append(newBlock) 33 | 34 | def validatingBlock(self, newBlock): 35 | previousBlock = self.getLatestBlock() 36 | if previousBlock.index + 1 != newBlock.index: 37 | return False 38 | elif previousBlock.hash != newBlock.previousHash: 39 | return False 40 | return True 41 | 42 | def hashMatchesDifficulty(self, hash, difficulty): 43 | hashBinary = binascii.unhexlify(hash) 44 | requiredPrefix = '0'*int(difficulty) 45 | return hashBinary.startswith(requiredPrefix) 46 | 47 | def findBlock(self, index, previousHash, timestamp, data, difficulty): 48 | nonce = 0 49 | while True: 50 | hash = self.calculateHash(index, previousHash, timestamp, data, difficulty, nonce) 51 | if self.hashMatchesDifficulty(hash, difficulty): 52 | block = Block(index, previousHash, timestamp, data, difficulty, nonce) 53 | return block 54 | nonce = nonce + 1 55 | 56 | def calculateHash(index, previousHash, timestamp, data, difficulty, nonce): 57 | return hashlib.sha256((str(index) + previousHash + str(timestamp) + data + str(difficulty) + str(nonce)).encode('utf-8')).hexdigest() 58 | -------------------------------------------------------------------------------- /aula-4.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import time 3 | import binascii 4 | 5 | class Block: 6 | def __init__(self, index, previousHash, timestamp, data, hash, difficulty, nonce): 7 | self.index = index 8 | self.previousHash = previousHash 9 | self.timestamp = timestamp 10 | self.data = data 11 | self.hash = hash 12 | self.difficulty = difficulty 13 | self.nonce = nonce 14 | 15 | 16 | class Blockchain: 17 | def __init__(self, genesisBlock): 18 | self.__chain = [] 19 | self.__chain.append(genesisBlock) 20 | self.DIFFICULTY_ADJUSTMENT = 10 21 | self.BLOCK_INTERVAL = 120 22 | 23 | def getLatestBlock(self): 24 | return self.__chain[-1] 25 | 26 | def generateNextBlock(self, data): 27 | previousBlock = self.getLatestBlock() 28 | nextIndex = previousBlock.index + 1 29 | nextTimestamp = int(round(time.time() * 1000)) 30 | nextPreviousHash = previousBlock.hash 31 | newBlock = Block(nextIndex, nextPreviousHash, nextTimestamp, data, 32 | calculateHash(nextIndex, nextPreviousHash, nextTimestamp, data)) 33 | if self.validatingBlock(newBlock) == True: 34 | self.__chain.append(newBlock) 35 | 36 | def validatingBlock(self, newBlock): 37 | previousBlock = self.getLatestBlock() 38 | if previousBlock.index + 1 != newBlock.index: 39 | return False 40 | elif previousBlock.hash != newBlock.previousHash: 41 | return False 42 | return True 43 | 44 | def hashMatchesDifficulty(self, hash, difficulty): 45 | hashBinary = binascii.unhexlify(hash) 46 | requiredPrefix = '0'*int(difficulty) 47 | return hashBinary.startswith(requiredPrefix) 48 | 49 | def findBlock(self, index, previousHash, timestamp, data, difficulty): 50 | nonce = 0 51 | while True: 52 | hash = self.calculateHash(index, previousHash, timestamp, data, difficulty, nonce) 53 | if self.hashMatchesDifficulty(hash, difficulty): 54 | block = Block(index, previousHash, timestamp, data, difficulty, nonce) 55 | return block 56 | nonce = nonce + 1 57 | 58 | def getDifficulty(self): 59 | latestBlock = self.getLatestBlock() 60 | if latestBlock.index % self.DIFFICULTY_ADJUSTMENT == 0 and latestBlock.index != 0: 61 | return self.getAdjustedDifficulty() 62 | else: 63 | return latestBlock.difficulty 64 | 65 | def getAdjustedDifficulty(self): 66 | latestBlock = self.getLatestBlock() 67 | prevAdjustmentBlock = self.__chain[len(self.__chain) - self.DIFFICULTY_ADJUSTMENT] 68 | timeExpected = self.BLOCK_INTERVAL * self.DIFFICULTY_ADJUSTMENT 69 | timeTaken = latestBlock.timestamp - prevAdjustmentBlock.timestamp 70 | if timeTaken < timeExpected / 2: 71 | return prevAdjustmentBlock.difficulty + 1 72 | elif timeTaken > timeExpected * 2: 73 | return prevAdjustmentBlock.difficulty - 1 74 | else: 75 | return prevAdjustmentBlock.difficulty 76 | 77 | 78 | def calculateHash(index, previousHash, timestamp, data, difficulty, nonce): 79 | return hashlib.sha256((str(index) + previousHash + str(timestamp) + data + str(difficulty) + str(nonce)).encode('utf-8')).hexdigest() 80 | 81 | -------------------------------------------------------------------------------- /aula-5.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import binascii 3 | 4 | class Transaction: 5 | def __init__(self): 6 | self.id = None 7 | self.inputs = None 8 | self.outputs = None 9 | 10 | class Output: 11 | def __init__(self, address, amount): 12 | self.address = address 13 | self.amount = amount 14 | 15 | class Input: 16 | def __init__(self): 17 | self.outputId = None 18 | self.outputIndex = None 19 | self.signature = None 20 | 21 | def idTransaction(transaction): 22 | inputContents = "" 23 | outputContents = "" 24 | for inpt in transaction.inputs: 25 | inputContents += (inpt.outputId + inpt.outputIndex) 26 | for output in transaction.outputs: 27 | outputContents += (output.address + output.amount) 28 | return hashlib.sha256((str(inputContents) + str(outputContents)).encode('utf-8')).hexdigest() 29 | -------------------------------------------------------------------------------- /aula-6.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import binascii 3 | from ecdsa import SigningKey, NIST384p 4 | 5 | class Transaction: 6 | def __init__(self): 7 | self.id = None 8 | self.inputs = None 9 | self.outputs = None 10 | 11 | class Output: 12 | def __init__(self, address, amount): 13 | self.address = address 14 | self.amount = amount 15 | 16 | class Input: 17 | def __init__(self): 18 | self.outputId = None 19 | self.outputIndex = None 20 | self.signature = None 21 | 22 | 23 | class UnspentOutput: 24 | def __init__(self, outputId, outputIndex, address, amount): 25 | self.outputId = outputId 26 | self.outputIndex = outputIndex 27 | self.address = address 28 | self.amount = amount 29 | 30 | class UnspentOutputs: 31 | def __init__(self): 32 | self.__listUtxo = [] 33 | 34 | def updateListUtxo(self, newList): 35 | self.__listUtxo = newList 36 | 37 | def newUnspentOutputs(self, transactions): 38 | utxoList = [] 39 | for transaction in transactions: 40 | for inpt in transaction.inputs: 41 | utxo = UnspentOutput(transaction.id, inpt.outputId, inpt.outputIndex, inpt.address, inpt.amount) 42 | utxoList.append(utxo) 43 | self.updateListUtxo(utxoList) 44 | 45 | 46 | def findUnspentOutput(outputId, outputIndex, listUnspentOutput): 47 | for unspentOutput in listUnspentOutput: 48 | if unspentOutput.outputId == outputId and unspentOutput.outputIndex == outputIndex: 49 | return True 50 | return False 51 | 52 | def transactionId(transaction): 53 | inputContents = "" 54 | outputContents = "" 55 | for inpt in transaction.inputs: 56 | inputContents += (inpt.outputId + inpt.outputIndex) 57 | for output in transaction.outputs: 58 | outputContents += (output.address + output.amount) 59 | return hashlib.sha256((str(inputContents) + str(outputContents).encode('utf-8')).hexdigest() 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /aula-7.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import binascii 3 | from ecdsa import SigningKey, NIST384p 4 | 5 | class Transaction: 6 | def __init__(self): 7 | self.id = None 8 | self.inputs = None 9 | self.outputs = None 10 | 11 | class Output: 12 | def __init__(self, address, amount): 13 | self.address = address 14 | self.amount = amount 15 | 16 | class Input: 17 | def __init__(self): 18 | self.outputId = None 19 | self.outputIndex = None 20 | self.signature = None 21 | 22 | class UnspentOutput: 23 | def __init__(self, outputId, outputIndex, address, amount): 24 | self.outputId = outputId 25 | self.outputIndex = outputIndex 26 | self.address = address 27 | self.amount = amount 28 | 29 | class UnspentOutputs: 30 | def __init__(self): 31 | self.__listUtxo = [] 32 | 33 | def updateListUtxo(self, newList): 34 | self.__listUtxo = newList 35 | 36 | def newUnspentOutputs(self, transactions): 37 | utxoList = [] 38 | for transaction in transactions: 39 | for inpt in transaction.inputs: 40 | utxo = UnspentOutput(transaction.id, inpt.outputId, inpt.outputIndex, inpt.address, inpt.amount) 41 | utxoList.append(utxo) 42 | self.updateListUtxo(utxoList) 43 | 44 | def findUnspentOutput(outputId, outputIndex, listUnspentOutput): 45 | for unspentOutput in listUnspentOutput: 46 | if unspentOutput.outputId == outputId and unspentOutput.outputIndex == outputIndex: 47 | return True 48 | return False 49 | 50 | def createSigningKeys(): 51 | return SigningKey.generate(curve=NIST384p) 52 | 53 | 54 | def signingInput(transaction, inputIndex, listUnspentOutput, privateKey): 55 | inpt = transaction.inputs[inputIndex] 56 | data = transaction.id 57 | verifyingUtxo = findUnspentOutput(inpt.outputId, inpt.outputIndex, listUnspentOutput) 58 | return privateKey.sign(data) 59 | 60 | def validatingInputs(input, transaction, unspentOutputs): 61 | for utxo in unspentOutputs: 62 | if utxo.outputId == input.outputId and utxo.outputIndex == input.outputIndex: 63 | address = utxo.address 64 | key = address.get_verifying_key() 65 | return key.verify(input.signature, transaction.id) 66 | return False 67 | 68 | def transactionId(transaction): 69 | inputContents = "" 70 | outputContents = "" 71 | for inpt in transaction.inputs: 72 | inputContents += (inpt.outputId + inpt.outputIndex) 73 | for output in transaction.outputs: 74 | outputContents += (output.address + output.amount) 75 | return hashlib.sha256((str(inputContents) + str(outputContents).encode('utf-8')).hexdigest() 76 | 77 | def validatingTransactionId(id, transaction): 78 | return (transactionId(transaction) == id) 79 | 80 | 81 | --------------------------------------------------------------------------------