예제 #1
0
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
                          })
예제 #2
0
    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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
 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
예제 #6
0
 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})
예제 #7
0
    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
예제 #8
0
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)