Ejemplo n.º 1
0
////////////////////////////////////////////////////////////////////////////////
//
// 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")
	}

}
Ejemplo n.º 2
0
////////////////////////////////////////////////////////////////////////////////
//
// 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)
	}
}