//////////////////////////////////////////////////////////////////////////////// // // main // //////////////////////////////////////////////////////////////////////////////// func main() { var X []*MinimalConnectionManager // Create nodes for i := 0; i < Cfg_simu_num_node; i++ { cm := MinimalConnectionManager{} // Reason for mutual registration: (1) when conn man receives // messages, it needs to notify the node; (2) when node has // processed a mesage, it might need to use conn man to send // some data out. nodePtr := consensus.NewConsensusParticipantPtr(&cm) cm.theNodePtr = nodePtr X = append(X, &cm) } // Contemplate connecting nodes into a thick circle: n := len(X) for i := 0; i < n; i++ { cm := X[i] c_left := int(Cfg_simu_fanout_per_node / 2) c_right := Cfg_simu_fanout_per_node - c_left for c := 0; c < c_left; c++ { j := (i - 1 - c + n) % n cm.RegisterPublisher(X[j]) } for c := 0; c < c_right; c++ { j := (i + 1 + c) % n cm.RegisterPublisher(X[j]) } } // // Request connections // for i := 0; i < n; i++ { X[i].RequestConnectionToAllMyPublisher() } { // // Choose a node to be a block-maker // index := mathrand.Intn(Cfg_simu_num_node) nodePtr := X[index].GetNode() // // Make a block (actually, only a header) // x := secp256k1.RandByte(888) // Random data. h := cipher.SumSHA256(x) // Its hash. b := consensus.BlockBase{} b.Init( nodePtr.SignatureOf(h), h, 0) // // Send it to subscribers. The subscribers are also publishers; // they send (forward, to be exact) the header to thire respective // listeners etc. // nodePtr.OnBlockHeaderArrived(&b) } // // Print the state of each node for a review or debugging. // for i, _ := range X { fmt.Printf("FILE_FinalState.txt|NODE i=%d ", i) X[i].GetNode().Print() fmt.Printf("\n") } }
//////////////////////////////////////////////////////////////////////////////// // // main // //////////////////////////////////////////////////////////////////////////////// func main() { cmd_line_args_process() // PERFORMANCE: cipher.DebugLevel1 = false cipher.DebugLevel2 = false var X []*MinimalConnectionManager var hack_global_seqno uint64 = 0 seed := "hdhdhdkjashfy7273" _, SecKeyArray := cipher.GenerateDeterministicKeyPairsSeed([]byte(seed), Cfg_simu_num_node) for i := 0; i < Cfg_simu_num_node; i++ { cm := MinimalConnectionManager{} // Reason for mutual registration: (1) when conn man receives // messages, it needs to notify the node; (2) when node has // processed a mesage, it might need to use conn man to send // some data out. nodePtr := consensus.NewConsensusParticipantPtr(&cm) s := SecKeyArray[i] nodePtr.SetPubkeySeckey(cipher.PubKeyFromSecKey(s), s) cm.theNodePtr = nodePtr X = append(X, &cm) } if false { fmt.Printf("Got %d nodes\n", len(X)) } if Cfg_simu_topology_is_random { fmt.Printf("CONFIG Topology: connecting %d nodes randomly with approx"+ " %d nearest-neighbors in and approx %d nearest-neighbors out.\n", Cfg_simu_num_node, Cfg_simu_fanout_per_node, Cfg_simu_fanout_per_node) for i, _ := range X { cm := X[i] for g := 0; g < Cfg_simu_fanout_per_node; g++ { j := mathrand.Intn(Cfg_simu_num_node) if i != j { cm.RegisterPublisher(X[j]) } } } } else { fmt.Printf("CONFIG Topology: connecting %d nodes via one (thick)"+ " circle with approx %d nearest-neighbors in and approx %d "+ "nearest-neighbors out.\n", Cfg_simu_num_node, Cfg_simu_fanout_per_node, Cfg_simu_fanout_per_node) n := len(X) for i := 0; i < n; i++ { cm := X[i] c_left := int(Cfg_simu_fanout_per_node / 2) c_right := Cfg_simu_fanout_per_node - c_left for c := 0; c < c_left; c++ { j := (i - 1 - c + n) % n cm.RegisterPublisher(X[j]) } for c := 0; c < c_right; c++ { j := (i + 1 + c) % n cm.RegisterPublisher(X[j]) } } } // Connect. PROD: This should request connections. The // connections can be accepted, rejected or never answered. Such // replies are asynchronous. SIMU: we connect synchronously. for i, _ := range X { X[i].RequestConnectionToAllMyPublisher() } global_seqno2h := make(map[uint64]cipher.SHA256) global_seqno2h_alt := make(map[uint64]cipher.SHA256) iter := 0 block_round := 0 done_processing_messages := false for ; iter < Cfg_simu_num_iter; iter++ { if true { if block_round < Cfg_simu_num_block_round { // NOTE: Propagating blocks from here is a // simplification/HACK: it implies that we have // knowledge of when messaging due to previous // activity (blocks and connections) has // stopped. Again, we make blocks from here for // debugging and testing only. //x := secp256k1.RandByte(888) // Random data in SIMU. x := make([]byte, 888) mathrand.Read(x) h := cipher.SumSHA256(x) // Its hash. //x_alt := secp256k1.RandByte(888) // Random data in SIMU. x_alt := make([]byte, 888) mathrand.Read(x) h_alt := cipher.SumSHA256(x_alt) // Its hash. global_seqno2h[hack_global_seqno] = h global_seqno2h_alt[hack_global_seqno] = h_alt indices := get_random_index_subset(Cfg_simu_num_node, Cfg_simu_num_blockmaker) if Cfg_debug_show_block_maker { fmt.Printf("block_round=%d, Random indices of block-"+ "makers: %v\n", block_round, indices) } n_forkers := int(Cfg_simu_prob_malicious * float64(len(indices))) for i := 0; i < len(indices); i++ { // TODO: Have many nodes send same block, and a few nodes // send a different block. Research the conditions under // which the block published by the majority would // dominate the other one. index := indices[i] nodePtr := X[index].GetNode() malicious := (i < n_forkers) duplicate := (mathrand.Float64() < Cfg_simu_prob_duplicate) ph := &h if malicious { ph = &h_alt } rep := 1 if duplicate { rep = 2 } // // WARNING: In a reslistic simulation, one would // need to remove the assumption of knowing global // properties such as 'hack_global_seqno' // if malicious { fmt.Printf(">>>>>> NODE (index,pubkey)=(%d,%s) is"+ " publishing ALTERNATIVE block\n", index, nodePtr.Pubkey.Hex()[:8]) } for j := 0; j < rep; j++ { // Signing same hash multipe times produces different // signatures (for a good reason). We do it // here to test if malicious re-publishing is // detected properly. propagate_hash_from_node(*ph, nodePtr, true, hack_global_seqno) } } hack_global_seqno += 1 block_round += 1 } else { done_processing_messages = true break // <<<<<<<< } } } zzz := "done" if !done_processing_messages { zzz = "***NOT done***" } fmt.Printf("Done (i) making Blocks, %s (ii) processing responses."+ " See stats on the next few lines. Used iterations=%d, unused"+ " iterations=%d. Exiting the event loop now.\n", zzz, iter, Cfg_simu_num_iter-iter) print_stat(X, iter) if Cfg_debug_node_final_state { for i, _ := range X { fmt.Printf("FILE_FinalState.txt|NODE i=%d ", i) X[i].GetNode().Print() fmt.Printf("\n") } } if Cfg_debug_node_summary { Simulate_compare_node_StateQueue(X, global_seqno2h, global_seqno2h_alt) } }