def _initialization(): if config.IS_NODE_0: print("I am Node 0") print(config.NUMBER_OF_NODES) blockchain.initialize(config.NUMBER_OF_NODES, 0, config.CAPACITY, config.DIFFICULTY) blockchainApi.setIp({ 0: { 'ipAddr': config.NODE_0_IP_ADDRESS, 'port': config.NODE_0_PORT } }) else: node_0_url = "http://" + config.NODE_0_IP_ADDRESS + ":" + config.NODE_0_PORT r = requests.get(node_0_url + "/initialisation", json={"port": environ.get('FLASK_RUN_PORT')}) nodeId = r.json()["nodeId"] blockchain.initialize(config.NUMBER_OF_NODES, nodeId, config.CAPACITY, config.DIFFICULTY) print(nodeId) pubKey = wallet.get_public_key().dumps() r = requests.post(node_0_url + "/finalisation", json={ "nodeId": nodeId, "pubKey": pubKey })
def is_genesis(self) -> bool: recipient = wallet.get_public_key(0).dumpb() if self.recipient != recipient: return False amount = 100 * util.get_nodes() if self.amount != amount: return False if self.inputs != [TransactionInput(b"0", 0)]: return False if self.sender != b"0": return False if len(self.outputs) != 2: return False out0 = self.outputs[0] if not (out0.index == 0 and \ out0.recipient == recipient and \ out0.amount == amount): return False out1 = self.outputs[1] if not (out1.index == 1 and \ out1.recipient == b"0" and \ out1.amount == 0): return False if self.id != self.hash(): return False if self.signature != b"0": return False return True
def generate_transaction(recipient_id: int, amount: float, mute: bool = False) -> bool: """If possible (there are enough UTXOs) generate a new transaction giving amount NBC to recipient and the change back to us. If mute is True don't broadcast it.""" logging.debug("Transaction requested: %f NBC to node %d", amount, recipient_id) sender = wallet.get_public_key().dumpb() recipient = wallet.get_public_key(recipient_id).dumpb() r = util.get_db() inputs: List[TransactionInput] = [] input_amount = 0.0 with r.lock("blockchain:tx_pool:lock"), \ r.lock("blockchain:utxo-tx:lock"): for ib, ob in r.hgetall("blockchain:utxo-tx").items(): o = TransactionOutput.loadb(ob) if o.recipient == sender: inputs.append(TransactionInput.loadb(ib)) input_amount += o.amount if input_amount >= amount: t = Transaction(recipient=recipient, amount=amount, inputs=inputs, input_amount=input_amount) # Add to transaction pool r.hset("blockchain:tx_pool", t.id, t.dumpb()) # "Add to wallet if mine" r.hdel("blockchain:utxo-tx", *(i.dumpb() for i in t.inputs)) r.hmset("blockchain:utxo-tx", {TransactionInput(t.id, o.index).dumpb(): \ o.dumpb() for o in t.outputs}) break else: # Not enough UTXOs logging.error("Cannot send %f NBC to node %d (not enough coins)", amount, recipient_id) return False logging.debug("Generated transaction %s", util.bintos(t.id)) _check_for_new_block() if not mute: logging.debug("Broadcasting transaction %s", util.bintos(t.id)) chatter.broadcast_transaction(t, util.get_peer_ids()) return True
def get_balance(node_id: Optional[int] = None) -> float: """If node_id is None, return current node's balance""" logging.debug("Balance requested for node %s", "local" if node_id is None else str(node_id)) keyb = wallet.get_public_key(node_id).dumpb() r = util.get_db() with r.lock("blockchain:utxo-tx:lock"): utxo_tx = r.hvals("blockchain:utxo-tx") balance = 0.0 for outb in utxo_tx: out = TransactionOutput.loadb(outb) if out.recipient == keyb: balance += out.amount logging.debug("Balance of node %s: %f", "local" if node_id is None else str(node_id), balance) return balance
def genesis() -> 'Transaction': recipient = wallet.get_public_key(0).dumpb() amount = 100 * util.get_nodes() gt = Transaction(recipient=recipient, amount=amount, inputs=[TransactionInput(b"0", 0)], input_amount=amount) gt.sender = b"0" gt.outputs = [ TransactionOutput(0, recipient, amount), TransactionOutput(1, b"0", 0) ] gt.id = gt.hash() gt.signature = b"0" return gt
def threadFn(): sleep(0.1 ) # wait a bit to make sure that the listener is started routingTable = {} for i in range(0, blockchainApi.getTotalNodes()): ipEntry = blockchainApi.getIp(i) pubKey = wallet.get_public_key(i).dumps() ipEntry.update({"pubKey": pubKey}) routingTable.update({i: ipEntry}) for i in range(1, blockchainApi.getTotalNodes()): ipEntry = blockchainApi.getIp(i) url = "http://" + ipEntry["ipAddr"] + ":" + str(ipEntry["port"] + \ "/finalisation") print("Sending to {} the routing table {}".format( i, routingTable)) requests.post(url, json={"routingTable": routingTable})
def __init__(self, recipient: bytes, amount: float, inputs: typing.Sequence[TransactionInput], input_amount: typing.Optional[float] = None, sender: typing.Optional[bytes] = None, outputs: typing.Optional[typing.Sequence[TransactionOutput]] = None, id_: typing.Optional[bytes] = None, signature: typing.Optional[bytes] = None) -> None: """ Create a new transaction to send coins. There are 2 use cases: - Creating a new transaction to send some coins: input_amount should be specified and equal the sum of the amounts of the outputs referenced by inputs. All other optional arguments should not be specified. - Creating a Transaction for an existing transaction (eg deserializing): sender, outputs, id_ and signature should be specified (input_amount is ignored). """ if not (isinstance(recipient, bytes) and \ isinstance(inputs, list) and \ all(isinstance(i, TransactionInput) for i in inputs)): raise TypeError self.recipient = recipient # TODO OPT: Is this necessary? (it's duplicated in the output) self.amount = float(amount) # TODO OPT: Is this necessary? (it's duplicated in the output) self.inputs = inputs if sender is None and outputs is None and id_ is None and signature is None: self.sender = wallet.get_public_key().dumpb() self.outputs = [ TransactionOutput(0, self.recipient, self.amount), TransactionOutput(1, self.sender, float(input_amount) - self.amount) # type: ignore ] self.id = self.hash() self.signature = wallet.sign(self.id) else: if not (isinstance(sender, bytes) and \ isinstance(outputs, list) and \ all(isinstance(o, TransactionOutput) for o in outputs) and \ isinstance(id_, bytes) and \ isinstance(signature, bytes)): raise TypeError self.sender = sender self.outputs = outputs self.id = id_ self.signature = signature
def test_wallet(): TEST_MESSAGE = b"This is a test message" wallet.generate_wallet(NODE_ID) signature = wallet.sign(TEST_MESSAGE) pubkey = wallet.get_public_key() assert pubkey.verify(TEST_MESSAGE, signature) assert PublicKey.loadb(pubkey.dumpb()) == pubkey assert PublicKey.loads(pubkey.dumps()) == pubkey # Load the predefined keys into a fresh wallet r = util.get_db() r.flushdb() util.set_nodes(NODES) util.set_node_id(NODE_ID) r.set("wallet:privkey", PRIVKEYSB[NODE_ID]) for node_id, key in enumerate(PUBKEYS): wallet.set_public_key(node_id=node_id, key=key)