Example #1
0
def transaction_checking(grid: MultiCircuit,
                         transactions: Transactions,
                         agent_id_to_grid_id,
                         dt=1):
    """
    Function that checks the transactions with electrical computations
    :param grid: GridCal grid Object
    :param transactions: Transactions object
    :param agent_id_to_grid_id: dictionary to relate the agent's id with the grid object's id
    :param dt: market interval in hours
    :return:
    """

    # declare the final transactions list
    final_transactions = Transactions()

    for transaction in transactions:

        hash = transaction_mine(grid, transaction, agent_id_to_grid_id, dt=dt)

        # if there are no errors
        if hash is not None:
            # modify the transaction, adding a hash based on the voltage
            transaction.hash = hash

            # store the transaction
            final_transactions.append(transaction)
        else:
            # since the transactions are sorted, if a critical state is found the rest are curtailed
            return final_transactions

    # return the approved transactions
    return final_transactions
Example #2
0
    def make_rows(self):
        import dateutil
        def get_increments(ledger, account):
            ld = ledger[ledger.idx].get_date(posting=ledger_account_name, return_string=False) if ledger.idx < len(ledger) else dateutil.parser.parse("2099/01/01")
            ad = account[account.idx].get_date(posting=ledger_account_name, return_string=False) if account.idx < len(account) else dateutil.parser.parse("2099/01/01")
                
            lbump = abump = False
            if ledger.idx == len(ledger):
                lbump = True
            if account.idx == len(account):
                abump = True
            if ledger.idx < len(ledger) and account.idx < len(account) and self.total(ledger[ledger.idx])==self.total(account[account.idx]):
                abump = lbump = True
            if ld <= ad:
                lbump = True
            if ld >= ad:
                abump = True
            ledger.bump = False
            if ledger.idx < len(ledger): ledger.bump = lbump
            account.bump = False
            if account.idx < len(account): account.bump = abump
        uncleared = Transactions()
        ret = ""
        ledger_account_name = c['banks'][self.account.bank_name]['accounts'][self.account.name]['ledger-account'].lower()
        while self.ledger.idx < len(self.ledger) or self.account.idx < len(self.account):
            if self.ledger.idx < len(self.ledger):
                if (self.ledger[self.ledger.idx]['state'] != "cleared" and 
                    not "cleared" in [p['state'] for p in self.ledger[self.ledger.idx]['postings'] if p['account_name'].lower().startswith(ledger_account_name)]):
                   uncleared.append(self.ledger[self.ledger.idx])
                   self.ledger.idx += 1
                   continue
            get_increments(self.ledger, self.account)

            if self.ledger.bump:
                self.ledger.total.append(self.ledger.total[-1] + self.total(self.ledger[self.ledger.idx]))
            if self.account.bump:
                self.account.total.append(self.account.total[-1] + self.total(self.account[self.account.idx]))

            if True:
                # make table row
                line = "<tr><td align='right'>"
                if self.ledger.bump: line += '{0}<br />'
                line += "</td><td>"
                if self.account.bump: line += '{1}<br />'
                line += "</td></tr>"
                ret += line.format(self.ledger[self.ledger.idx] if self.ledger.idx<len(self.ledger) else "", 
                                   self.account[self.account.idx] if self.account.idx < len(self.account) else "")
                if self.ledger.total[-1] == self.account.total[-1]:
                    ret += ("<tr><td align='right'><font color='green'>{0}</font><br /></td><td><font color='green'>{1}</font></td></tr>".
                            format(self.ledger.total[-1], self.account.total[-1]))
                else:
                    if self.ledger.bump == self.account.bump == True:
                        ret += ("<tr><td align='right'><font color='blue'>{0}</font><br /></td><td><font color='blue'>{1}</font></td></tr>".
                                format(self.ledger.total[-1], self.account.total[-1]))
                    else:
                        ret += "<tr><td align='right'>{0}<br /></td><td>{1}</td></tr>".format(self.ledger.total[-1], self.account.total[-1])

            if self.ledger.bump: self.ledger.idx += 1
            if self.account.bump: self.account.idx += 1

            # TODO: print the uncleared transactions in an intelligent way at the end.
            #if len(self.ledger) >= self.ledger.idx and len(self.account) >= self.account.idx:
            #    if len(uncleared) > 0:
            #        for tx in uncleared:
            #            print "<tr><td align='right'>{0}</td></tr>".format(tx)
        return ret
Example #3
0
class Blockchain:

    def __init__(self, agent_id_to_grid_id, fname='Grid.xlsx', dt=1):
        self.current_transactions = Transactions()
        self.chain = []
        self.nodes = set()

        self.agent_id_to_grid_id = agent_id_to_grid_id

        self.actors_group = ActorsGroup()

        self.market = Market(actors_group=self.actors_group)

        self.dt = dt

        self.grid = MultiCircuit()
        self.grid.load_file(fname)

        # Create the genesis block
        self.new_block(previous_hash='1', proof=100)

    def register_node(self, address):
        """
        Add a new node to the list of nodes

        :param address: Address of node. Eg. 'http://192.168.0.5:5000'
        """

        parsed_url = urlparse(address)
        if parsed_url.netloc:
            self.nodes.add(parsed_url.netloc)
        elif parsed_url.path:
            # Accepts an URL without scheme like '192.168.0.5:5000'.
            self.nodes.add(parsed_url.path)
        else:
            raise ValueError('Invalid URL')


    def valid_chain(self, chain):
        """
        Determine if a given blockchain is valid

        :param chain: A blockchain
        :return: True if valid, False if not
        """

        last_block = chain[0]
        current_index = 1

        while current_index < len(chain):
            block = chain[current_index]
            print(f'{last_block}')
            print(f'{block}')
            print("\n-----------\n")
            # Check that the hash of the block is correct
            last_block_hash = self.hash(last_block)
            if block['previous_hash'] != last_block_hash:
                return False

            # Check that the Proof of Work is correct
            if not self.valid_proof(last_block['proof'], block['proof'], last_block_hash):
                return False

            last_block = block
            current_index += 1

        return True

    def resolve_conflicts(self):
        """
        This is our consensus algorithm, it resolves conflicts
        by replacing our chain with the longest one in the network.

        :return: True if our chain was replaced, False if not
        """

        neighbours = self.nodes
        new_chain = None

        # We're only looking for chains longer than ours
        max_length = len(self.chain)

        # Grab and verify the chains from all the nodes in our network
        for node in neighbours:
            response = requests.get(f'http://{node}/chain')

            if response.status_code == 200:
                length = response.json()['length']
                chain = response.json()['chain']

                # Check if the length is longer and the chain is valid
                if length > max_length and self.valid_chain(chain):
                    max_length = length
                    new_chain = chain

        # Replace our chain if we discovered a new, valid chain longer than ours
        if new_chain:
            self.chain = new_chain
            return True

        return False

    def new_block(self, proof, previous_hash):
        """
        Create a new Block in the Blockchain

        :param proof: The proof given by the Proof of Work algorithm
        :param previous_hash: Hash of previous Block
        :return: New Block
        """

        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.chain[-1]),
        }

        # Reset the current list of transactions
        self.current_transactions = []

        self.chain.append(block)
        return block

    def new_transaction(self, sender, recipient, energy_amount, price, bid_type, electric_hash):
        """
        Creates a new transaction to go into the next mined Block

        :param sender: Address of the Sender
        :param recipient: Address of the Recipient
        :param amount: Amount
        :return: The index of the Block that will hold this transaction
        """

        tr = Transaction(bid_id=len(self.current_transactions),   # this may be repeated but it is only used to print
                         seller_id=sender, buyer_id=recipient, energy_amount=energy_amount,
                         price=price, bid_type=bid_type, bid_hash=electric_hash)

        # self.current_transactions.append({
        #     'sender': sender,
        #     'recipient': recipient,
        #     'energy_amount': energy_amount,
        #     'price': price,
        #     'bid_type': bid_type,
        #     'electric_hash': electric_hash
        # })

        self.current_transactions.append(tr)

        return self.last_block['index'] + 1

    @property
    def last_block(self):
        return self.chain[-1]

    @staticmethod
    def hash(block):
        """
        Creates a SHA-256 hash of a Block

        :param block: Block
        """

        # We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
        # block_string = json.dumps(block, sort_keys=True).encode()
        block_string = str(block['index']) + \
                       str(block['timestamp']) + \
                       str(block['proof']) + \
                       str(block['previous_hash']) + \
                       str([j.hash for j in block['transactions']])
        # block_string = block.

        # block_string = block.to_json()

        return hashlib.sha256(block_string.encode('UTF-8')).hexdigest()


    @staticmethod
    def valid_proof( proof ):
        """
        Validates the Proof

        :param proof: <int> Current Proof
        :return: <bool> True if correct, False if not.

        """

        return proof != None
Example #4
0
    def bid_matching(self):

        self.compute()

        prob = pulp.LpProblem("DC optimal power flow", pulp.LpMinimize)

        ni = len(self.demand_bids)
        nj = len(self.generation_bids)

        alpha = np.empty((ni, nj), dtype=object)

        # declare alpha
        for i, j in product(range(ni), range(nj)):
            alpha[i, j] = pulp.LpVariable('alpha_' + str(i) + '_' + str(j), 0,
                                          1)

        gen_slack = np.empty(nj, dtype=object)
        for j in range(nj):
            gen_slack[j] = pulp.LpVariable('gen_slack_' + str(j))

        # objective function
        f = 0
        for i, j in product(range(ni), range(nj)):
            f += self.demand_bids[i].energy_mw * alpha[
                i, j] * self.generation_bids[j].price
        prob += f  #+ sum(gen_slack)

        #
        for j in range(nj):
            d_alpha = 0
            for i in range(ni):
                d_alpha += self.demand_bids[i].energy_mw * alpha[i, j]
            prob += (d_alpha <= self.generation_bids[j].energy_mw
                     )  #+ gen_slack[j])

        # sum of alpha per demand contract must be one
        for i in range(ni):
            prob += (sum(alpha[i, :]) == 1.0)

        # solve
        prob.solve()
        prob.writeLP('problem.lp')
        prob.writeMPS('problem.mps')
        print("Status:", pulp.LpStatus[prob.status], prob.status)

        #  -------------------------------------------------------------------------------------------------------------
        #  Generate the transactions

        transactions = Transactions()

        # problem solved
        for i, j in product(range(ni), range(nj)):
            id_gen = self.generation_bids[j].id
            id_demnd = self.demand_bids[i].id
            demand = self.demand_bids[i].energy_mw
            price = self.generation_bids[j].price
            val = alpha[i, j].value()
            if val != 0:
                print(id_demnd, 'buys from', id_gen, 'alpha', val)
                tr = Transaction(bid_id=str(id_gen) + '_' + str(id_demnd),
                                 seller_id=id_gen,
                                 buyer_id=id_demnd,
                                 energy_amount=val * demand,
                                 price=price,
                                 bid_type=self.demand_bids[i].bid_type)
                transactions.append(tr)

        return sorted(transactions, key=lambda x: x.bid_type, reverse=False)