Skip to content

Instantly share code, notes, and snippets.

@bachase
Created July 12, 2017 16:59
Show Gist options
  • Save bachase/400cff1b3dc4e1a0d79d447f78f80378 to your computer and use it in GitHub Desktop.
Save bachase/400cff1b3dc4e1a0d79d447f78f80378 to your computer and use it in GitHub Desktop.
SimIdeas

Consensus Simulation Ideas

General simulation flow

  1. Specify the simulation parameters
    • Name node participants and groups
    • Parameters
  2. Specify the graph
    • Trust Edges
    • Network/Messaging edges
  3. Specify events/dynamic actions
    • How/when transactions are submitted
    • How/when network layers or trust relationships change
  4. Specify collectors/listeners
    • Could be "pure" that are output only
    • Closed-loop that listen and interact with network
  5. Run simulation

General Thoughts

  • Consistent names (nodes vs. peers)
  • Consistent types (NodeID vs uint32)
  • How much overlay algorithm needs to allow specialization?

Plan

  1. Create generic Digraph<Node, Edge> that stores as adjacency list? Just wrap boost::graph?
  2. Use this for TrustGraph and NetworkGraph/BasicNetwork
  3. Create NodeGroup and allow named aliases for sets of nodes
  4. Add graph builders (scalefree, ring, two-clique?)
    • Decide on interface .. use sim.trust or group.trust
  5. Overlay wrapper for BasicNetwork?
  6. UNL from trustgraph? Just provide reference to outEdges?
  7. JSON/.dot output and input?

Examples

Production with client handlers

Simulate the current production setup with 5 validators in a core group and a set of client handlers that receive the transactions.

Simulation s;
// NodeGroup is a light-weight reference to a set of nodes in the simulation
NodeGroup validators = s.createNodeGroup("Validators", 5);
NodeGroup handlers = s.createNodeGroup("ClientHandlers", 3);
NodeGroup network = validators + handlers;

for(Peer & handler : handlers)
{
    // Peer is the full peer class instance
    // peer.id() is the global unique ID for a peer
    handler.isValidator = false;
}

{
    // Version 1, use groups/nodes directly
    //  - UNL and network links are owned by each Peer?
    //  - Or still owend by Simulation

    validators.trust(validators);
    handlers.trust(validators);

    // all nodes connected to all other nodes
    network.link(network, 100ms);
}

{
    // Version 2, go through simulator
    // explicit for user
    s.trust(validators, validators);
    s.trust(handlers,validators);
    s.link(network, network, 100ms);
}

TxSubmitter txs{start,stop,rate/model};
txs.target(handlers);

Collector standardCollector;
s.addCollect(standardCollector);

// Run for 10 rounds
s.run(10);

// Report result
standardCollector.report();
MultiRegion
Simulation s;

NodeGroup northAmerica = s.createNodeGroup("NorthAmerica", 4);
NodeGroup southAmerica = s.createNodeGroup("SouthAmerica", 4);
NodeGroup europe = s.createNodeGroup("Europe", 4);
NodeGroup asia = s.createNodeGroup("Asia", 4);

// BEAST_EXPECT(s.nodeGroup("Europe") == europe)
// BEAST_EXPECT(europe(0) == s.node(europe(0).id()))
NodeGroup network = northAmerica + southAmerica + europe + asia;
// All nodes trust all other nodes
network.trust(network);

// Local network delays are small
for(auto & group : {northAmerica, southAmerica, europe, asia})
    northAmerica.connect(northAmerica, 10ms);

// NA to SA random 500 ms +/- 10 ms
s.network_delay(northAmerica, southAmerica, normal(500ms, 10ms));
...

// All txs submitted to Asia
TxSubmitter txs{args,...};
txs.target(asia);

LatencyCollector lc;
s.addCollector(lc);

// run for 1000 seconds of simulation time
s.run(1000s);

lc.printReport();
Graph primitives
Simulation s;

// Unnamed
NodeGroup network = s.createNodeGroup(100);
// Various trust primitives
// network.trust(T)
//   where T::operator(NodeGroup) sets trust relations
network.trust(network); // clique
network.trust(scaleFree{parms});
network.trust(ring{});
network.trust(tree{network[0], 4 /* children */});


// Network primitives
// network.link(T)
//  where T::operator(NodeGroup) sets connection/delay

network.link(network, DelayModel);
network.link(fromTrust{}, DelayModel);
network.link(scaleFree{parms}, DelayModel);
network.link(ring{}, DelayModel);

// Building things out

NodeGroup a = s.createNodeGroup("a",10);
NodeGroup b = s.createNodeGroup("b",10);

a.trust(a);
b.trust(b);

// Links one node of a to all of b
a[3].trust(b);
b.trust(a[3]);
Netsplits
Simulation s;

NodeGroup a = s.createNodeGroup("a", 20);
NodeGroup b = s.createNodeGroup("b", 20);
NodeGroup c = s.createNodeGroup("b", 30);
NodeGraph network = a + b + c;

network.trust(network);
// Should links really be directed?
a.link(b, DelayModel);
b.link(a, DelayModel);
b.link(c, DelayModel);
c.link(b, DelayModel);

// Register net split in the future
s.at(1000s, [&]()
{
    a.unlink(b);
    b.unlink(a);
    c.unlink(b);
    b.unlink(c);
});

s.addCollector(foo);
s.run(10000s);
From Graph Spec
Simulation s = Simulation::fromSpec("config.json/.dot");
// Prefer JSON so it can define node group/names
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment