Exemple #1
0
    def __init__(self, k, gamma):
        random.seed()
        # RangeBST lets you efficiently lookup nodes in a range of positions
        self.nodes = RangeBST()
        self.k = k
        self.gamma = gamma
        self.two_above_array = [1.0 / pow(2, i) for i in range(400)]

        self.quorums = {}
        self.log = 0
        self.redo_quorums()
Exemple #2
0
    def __init__(self, k, gamma):
        random.seed()
        # RangeBST lets you efficiently lookup nodes in a range of positions
        self.nodes = RangeBST()
        self.k = k
        self.gamma = gamma
        self.two_above_array = [1.0 / pow(2, i) for i in range(400)]

        self.quorums = {}
        self.log = 0
        self.redo_quorums()
Exemple #3
0
class CuckooNetwork(object):
    def __init__(self, k, gamma):
        random.seed()
        # RangeBST lets you efficiently lookup nodes in a range of positions
        self.nodes = RangeBST()
        self.k = k
        self.gamma = gamma
        self.two_above_array = [1.0 / pow(2, i) for i in range(400)]

        self.quorums = {}
        self.log = 0
        self.redo_quorums()

    def clone(self):
        c = CuckooNetwork(self.k, self.gamma)
        c.nodes = copy.deepcopy(self.nodes)
        c.quorums = self.quorums
        c.log = self.log
        return c

    def random_pos(self):
        return random.random()

    def __len__(self):
        return len(self.nodes)

    def two_above(self, val):
        if val >= 1.0:
            return 1.0
        # We've cached the 1/powers of 2 values in self.two_above_array
        for (r, aval) in enumerate(self.two_above_array):
            if val > aval:
                return self.two_above_array[r - 1]
            elif val == aval:
                return aval

        raise Exception("Unknown above")

    def k_region_nodes(self, pos):
        (start, end) = self.k_region(pos)
        return self.nodes.range(start, end)

    def k_region(self, pos):
        kr_size = self.k_region_size()
        reg = math.floor(pos / kr_size)
        return (kr_size * reg, kr_size * (reg + 1))

    def k_region_size(self):
        if len(self) == 0:
            return 1.0
        # Assume network knows log estimate of size
        # and not actual size
        n = float(pow(2, self.log))

        # Get the size of a k-region
        return self.two_above(self.k / n)

    def remove(self, node):
        self.remove_from_quorums(node)
        self.nodes.remove(node.pos)

        # Did we just shrink the network by a log size?
        # If so, it's time to adjust quorum size
        if len(self) == 0:
            self.quorums = {}
        elif int(math.log(len(self), 2)) < self.log:
            self.log = int(math.log(len(self), 2))
            self.redo_quorums()

    def remove_from_quorums(self, node):
        reg = self.quorum_region(node.pos)
        self.quorums[reg].remove(node)

    def add_to_quorums(self, node):
        reg = self.quorum_region(node.pos)
        self.quorums[reg].add(node)

    def bootstrap_join(self, node):
        node.pos = self.random_pos()
        self.nodes.add(node.pos, node)
        self.add_to_quorums(node)
        # Did we just grow the network by a log size?
        # If so, it's time to adjust quorum size
        if math.floor(math.log(len(self), 2)) > self.log:
            self.log = math.floor(math.log(len(self), 2))
            self.redo_quorums()

    def join(self, node, update_quorums=False):
        # Pick a random location
        rand = self.random_pos()
        evict = self.k_region_nodes(rand)

        # Reposition the other nodes in the k-region
        for evicted in evict:
            self.remove_from_quorums(evicted)
            self.nodes.remove(evicted.pos)

            # Secondary join (no evicting)
            evicted.pos = self.random_pos()
            self.nodes.add(evicted.pos, evicted)
            self.add_to_quorums(evicted)

        # Add the new node
        node.pos = rand
        self.add_to_quorums(node)
        self.nodes.add(node.pos, node)

        # Did we just grow the network by a log size?
        # If so, it's time to adjust quorum size
        if math.floor(math.log(len(self), 2)) > self.log:
            self.log = math.floor(math.log(len(self), 2))
            self.redo_quorums()

    def quorum_size(self, pos):
        reg = self.quorum_region(pos)
        return len(self.quorums[reg])

    def avg_quorum_size(self):
        sum = 0.0
        for q in self.quorums.itervalues():
            sum += len(q)
        return sum / len(self.quorums)

    def quorum_region_size(self):
        # gamma*log(n) k_regions
        # where gamma is a small integer
        if self.log == 0:
            return 1.0

        # Get the size of a k-region
        g = float(self.gamma)

        return self.two_above(self.k_region_size() * (g * self.log))

    def quorum_region(self, pos):
        q_size = self.quorum_region_size()
        reg = math.floor(pos / q_size)
        return (q_size * reg, q_size * (reg + 1))

    def redo_quorums(self):
        self.quorums = {}
        q_size = self.quorum_region_size()
        cur = 0.0
        while cur < 1.0:
            self.quorums[(cur, cur + q_size)] = set()
            cur += q_size

        for node in self.nodes:
            r = self.quorum_region(node.pos)
            self.quorums[r].add(node)

    def verify(self):

        # Verify each quorum region has no more than 1/4 byzantine
        for quorum in self.quorums.itervalues():
            bad = len([1 for n in quorum if n.byzantine])

            if float(bad) / len(quorum) > 0.25:
                return False
        return True

    def byzantine_from_least_faulty_quorum(self):
        faultiness = {}
        for (r, quorum) in self.quorums.iteritems():
            bad = len([1 for n in quorum if n.byzantine])
            faultiness[r] = float(bad) / len(quorum)

        # Find the least faulty
        least = (1.1, None)
        for (r, fault) in faultiness.iteritems():
            if fault < least[0] and fault > 0.0:
                least = (fault, r)

        least_q = self.quorums[least[1]]
        # return the first byzantine node in this quorum
        for node in least_q:
            if node.byzantine:
                return node

        raise Exception("No node found")
Exemple #4
0
class CuckooNetwork(object):
    def __init__(self, k, gamma):
        random.seed()
        # RangeBST lets you efficiently lookup nodes in a range of positions
        self.nodes = RangeBST()
        self.k = k
        self.gamma = gamma
        self.two_above_array = [1.0 / pow(2, i) for i in range(400)]

        self.quorums = {}
        self.log = 0
        self.redo_quorums()

    def clone(self):
        c = CuckooNetwork(self.k, self.gamma)
        c.nodes = copy.deepcopy(self.nodes)
        c.quorums = self.quorums
        c.log = self.log
        return c

    def random_pos(self):
        return random.random()

    def __len__(self):
        return len(self.nodes)

    def two_above(self, val):
        if val >= 1.0:
            return 1.0
        # We've cached the 1/powers of 2 values in self.two_above_array
        for (r, aval) in enumerate(self.two_above_array):
            if val > aval:
                return self.two_above_array[r - 1]
            elif val == aval:
                return aval

        raise Exception("Unknown above")

    def k_region_nodes(self, pos):
        (start, end) = self.k_region(pos)
        return self.nodes.range(start, end)

    def k_region(self, pos):
        kr_size = self.k_region_size()
        reg = math.floor(pos / kr_size)
        return (kr_size * reg, kr_size * (reg + 1))

    def k_region_size(self):
        if len(self) == 0:
            return 1.0
        # Assume network knows log estimate of size
        # and not actual size
        n = float(pow(2, self.log))

        # Get the size of a k-region
        return self.two_above(self.k / n)

    def remove(self, node):
        self.remove_from_quorums(node)
        self.nodes.remove(node.pos)

        # Did we just shrink the network by a log size?
        # If so, it's time to adjust quorum size
        if len(self) == 0:
            self.quorums = {}
        elif int(math.log(len(self), 2)) < self.log:
            self.log = int(math.log(len(self), 2))
            self.redo_quorums()

    def remove_from_quorums(self, node):
        reg = self.quorum_region(node.pos)
        self.quorums[reg].remove(node)

    def add_to_quorums(self, node):
        reg = self.quorum_region(node.pos)
        self.quorums[reg].add(node)

    def bootstrap_join(self, node):
        node.pos = self.random_pos()
        self.nodes.add(node.pos, node)
        self.add_to_quorums(node)
        # Did we just grow the network by a log size?
        # If so, it's time to adjust quorum size
        if math.floor(math.log(len(self), 2)) > self.log:
            self.log = math.floor(math.log(len(self), 2))
            self.redo_quorums()

    def join(self, node, update_quorums=False):
        # Pick a random location
        rand = self.random_pos()
        evict = self.k_region_nodes(rand)

        # Reposition the other nodes in the k-region
        for evicted in evict:
            self.remove_from_quorums(evicted)
            self.nodes.remove(evicted.pos)

            # Secondary join (no evicting)
            evicted.pos = self.random_pos()
            self.nodes.add(evicted.pos, evicted)
            self.add_to_quorums(evicted)

        # Add the new node
        node.pos = rand
        self.add_to_quorums(node)
        self.nodes.add(node.pos, node)

        # Did we just grow the network by a log size?
        # If so, it's time to adjust quorum size
        if math.floor(math.log(len(self), 2)) > self.log:
            self.log = math.floor(math.log(len(self), 2))
            self.redo_quorums()

    def quorum_size(self, pos):
        reg = self.quorum_region(pos)
        return len(self.quorums[reg])

    def avg_quorum_size(self):
        sum = 0.0
        for q in self.quorums.itervalues():
            sum += len(q)
        return sum / len(self.quorums)

    def quorum_region_size(self):
        # gamma*log(n) k_regions
        # where gamma is a small integer
        if self.log == 0:
            return 1.0

        # Get the size of a k-region
        g = float(self.gamma)

        return self.two_above(self.k_region_size() * (g * self.log))

    def quorum_region(self, pos):
        q_size = self.quorum_region_size()
        reg = math.floor(pos / q_size)
        return (q_size * reg, q_size * (reg + 1))

    def redo_quorums(self):
        self.quorums = {}
        q_size = self.quorum_region_size()
        cur = 0.0
        while cur < 1.0:
            self.quorums[(cur, cur + q_size)] = set()
            cur += q_size

        for node in self.nodes:
            r = self.quorum_region(node.pos)
            self.quorums[r].add(node)

    def verify(self):

        # Verify each quorum region has no more than 1/4 byzantine
        for quorum in self.quorums.itervalues():
            bad = len([1 for n in quorum if n.byzantine])

            if float(bad) / len(quorum) > 0.25:
                return False
        return True

    def byzantine_from_least_faulty_quorum(self):
        faultiness = {}
        for (r, quorum) in self.quorums.iteritems():
            bad = len([1 for n in quorum if n.byzantine])
            faultiness[r] = float(bad) / len(quorum)

        # Find the least faulty
        least = (1.1, None)
        for (r, fault) in faultiness.iteritems():
            if fault < least[0] and fault > 0.0:
                least = (fault, r)

        least_q = self.quorums[least[1]]
        # return the first byzantine node in this quorum
        for node in least_q:
            if node.byzantine:
                return node

        raise Exception("No node found")