Esempio n. 1
0
// Basic test for reed-solomon coding, verifies that standard input
// will produce the correct results.
func TestCoding(t *testing.T) {
	k := 100
	m := common.QuorumSize - k
	bytesPerSegment := 1024

	randomBytes, err := crypto.RandomByteSlice(bytesPerSegment * k)
	if err != nil {
		t.Fatal(err)
	}

	// get hash of original file
	randomBytesHash, err := crypto.CalculateHash(randomBytes)
	if err != nil {
		t.Fatal(err)
	}

	// encode original file into a data ring
	ringSegments, err := EncodeRing(k, bytesPerSegment, randomBytes)
	if err != nil {
		t.Fatal(err)
	}

	// verify that first k segments are still original data
	originalDataHash, err := crypto.CalculateHash(randomBytes)
	if err != nil {
		t.Fatal(err)
	} else if originalDataHash != randomBytesHash {
		t.Fatal("original data was modified after caling EncodeRing!")
	}

	// reduce file to a set of k segments and print those segments out
	remainingSegments := make([]string, k)
	segmentIndicies := make([]uint8, k)
	for i := m; i < common.QuorumSize; i++ {
		remainingSegments[i-m] = ringSegments[i]
		segmentIndicies[i-m] = uint8(i)
	}

	// recover original data
	recoveredData, err := RebuildSector(k, bytesPerSegment, remainingSegments, segmentIndicies)
	if err != nil {
		t.Fatal(err)
	}

	// compare to hash of data when first generated
	recoveredDataHash, err := crypto.CalculateHash(recoveredData)
	if err != nil {
		t.Fatal(err)
	} else if recoveredDataHash != randomBytesHash {
		t.Fatal("recovered data is different from original data")
	}

	// In every test, we check that the hashes equal
	// every other hash that gets created. This makes
	// me uneasy.
}
Esempio n. 2
0
// Basic test for reed-solomon coding, verifies that standard input
// will produce the correct results.
func TestCoding(t *testing.T) {
	// set encoding parameters
	k := common.QuorumSize / 2
	m := common.QuorumSize - k
	b := 1024

	// create sector data
	randomBytes, err := crypto.RandomByteSlice(b * k)
	if err != nil {
		t.Fatal(err)
	}

	// create sector
	sec, err := common.NewSector(randomBytes)
	if err != nil {
		t.Fatal(err)
	}

	// calculate encoding parameters
	params := sec.CalculateParams(k)

	// encode data into a Ring
	ring, err := EncodeRing(sec, params)
	if err != nil {
		t.Fatal(err)
	}

	// create Ring from subset of encoded segments
	var newRing []common.Segment
	for i := m; i < common.QuorumSize; i++ {
		newRing = append(newRing, ring[i])
	}

	// recover original data
	newSec, err := RebuildSector(newRing, params)
	if err != nil {
		t.Fatal(err)
	}

	// compare to hash of data when first generated
	recoveredDataHash, err := crypto.CalculateHash(newSec.Data)
	if err != nil {
		t.Fatal(err)
	} else if recoveredDataHash != sec.Hash {
		t.Fatal("recovered data is different from original data")
	}

	// In every test, we check that the hashes equal
	// every other hash that gets created. This makes
	// me uneasy.
}
Esempio n. 3
0
// uploadSector splits a Sector into a Ring and distributes it across a quorum.
// It hashes each of the Ring's segments and stores the hashes in the SectorDB.
func uploadSector(sec *common.Sector) (err error) {
	// look up Sector in SectorDB
	rh := SectorDB[sec.Hash]
	if rh == nil {
		return fmt.Errorf("Sector not found in database")
	}

	// create ring
	ring, err := erasure.EncodeRing(sec, rh.Params)
	if err != nil {
		return
	}

	// calculate and store segment hashes
	for i := range ring {
		rh.SegHashes[i], err = crypto.CalculateHash(ring[i].Data)
		if err != nil {
			return
		}
	}

	// for now we just send segment i to host i
	// this may need to be randomized for security
	for i := range rh.Hosts {
		err = router.SendMessage(&common.Message{
			Dest: rh.Hosts[i],
			Proc: "Server.UploadSegment",
			Args: ring[i],
			Resp: nil,
		})
		if err != nil {
			return
		}
	}

	return
}
Esempio n. 4
0
// TestRPCUploadSector tests the NewRPCServer and uploadFile functions.
// NewRPCServer must properly initialize a RPC server.
// uploadSector must succesfully distribute a Sector among a quorum.
// The uploaded Sector must be successfully reconstructed.
func TestRPCuploadSector(t *testing.T) {
	SectorDB = make(map[crypto.Hash]*common.RingHeader)

	// create RPCServer
	var err error
	router, err = network.NewRPCServer(9985)
	if err != nil {
		t.Fatal("Failed to initialize RPCServer:", err)
	}
	defer router.Close()

	// create quorum
	var q [common.QuorumSize]common.Address
	var shs [common.QuorumSize]Server
	for i := 0; i < common.QuorumSize; i++ {
		q[i] = common.Address{0, "localhost", 9000 + i}
		qrpc, err := network.NewRPCServer(9000 + i)
		defer qrpc.Close()
		if err != nil {
			t.Fatal("Failed to initialize RPCServer:", err)
		}
		q[i].ID = qrpc.RegisterHandler(&shs[i])
	}

	// create sector
	secData, err := crypto.RandomByteSlice(70000)
	if err != nil {
		t.Fatal("Could not generate test data:", err)
	}

	sec, err := common.NewSector(secData)
	if err != nil {
		t.Fatal("Failed to create sector:", err)
	}

	// add sector to database
	k := common.QuorumSize / 2
	SectorDB[sec.Hash] = &common.RingHeader{
		Hosts:  q,
		Params: sec.CalculateParams(k),
	}

	// upload sector to quorum
	err = uploadSector(sec)
	if err != nil {
		t.Fatal("Failed to upload file:", err)
	}

	// rebuild file from first k segments
	var newRing []common.Segment
	for i := 0; i < k; i++ {
		newRing = append(newRing, shs[i].seg)
	}

	sec, err = erasure.RebuildSector(newRing, SectorDB[sec.Hash].Params)
	if err != nil {
		t.Fatal("Failed to rebuild file:", err)
	}

	// check hash
	rebuiltHash, err := crypto.CalculateHash(sec.Data)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	if sec.Hash != rebuiltHash {
		t.Fatal("Failed to recover file: hashes do not match")
	}
}
Esempio n. 5
0
// TestRPCdownloadSector tests the NewRPCServer and downloadSector functions.
// NewRPCServer must properly initialize a RPC server.
// downloadSector must successfully retrieve a Sector from a quorum.
// The downloaded Sector must match the original Sector.
func TestRPCdownloadSector(t *testing.T) {
	SectorDB = make(map[crypto.Hash]*common.RingHeader)

	// create sector
	secData, err := crypto.RandomByteSlice(70000)
	if err != nil {
		t.Fatal("Could not generate test data:", err)
	}

	sec, err := common.NewSector(secData)
	if err != nil {
		t.Fatal("Failed to create sector:", err)
	}

	k := common.QuorumSize / 2
	params := sec.CalculateParams(k)

	// encode sector
	ring, err := erasure.EncodeRing(sec, params)
	if err != nil {
		t.Fatal("Failed to encode sector data:", err)
	}

	// create RPCServer
	router, err = network.NewRPCServer(9985)
	if err != nil {
		t.Fatal("Failed to initialize RPCServer:", err)
	}
	defer router.Close()

	// create quorum
	var q [common.QuorumSize]common.Address
	for i := 0; i < common.QuorumSize; i++ {
		q[i] = common.Address{0, "localhost", 9000 + i}
		qrpc, err := network.NewRPCServer(9000 + i)
		if err != nil {
			t.Fatal("Failed to initialize RPCServer:", err)
		}
		sh := new(Server)
		sh.seg = ring[i]
		q[i].ID = qrpc.RegisterHandler(sh)
	}

	// add sector to database
	SectorDB[sec.Hash] = &common.RingHeader{
		Hosts:  q,
		Params: params,
	}

	// download file from quorum
	sec, err = downloadSector(sec.Hash)
	if err != nil {
		t.Fatal("Failed to download file:", err)
	}

	// check hash
	rebuiltHash, err := crypto.CalculateHash(sec.Data)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	if sec.Hash != rebuiltHash {
		t.Fatal("Failed to recover file: hashes do not match")
	}
}
Esempio n. 6
0
func main() {
	router, _ = network.NewRPCServer(9989)
	defer router.Close()
	SectorDB = make(map[crypto.Hash]*common.RingHeader)
	var (
		input string
		q     common.Quorum
		s     *common.Sector
		h     crypto.Hash
		err   error
	)
	for {
		fmt.Print("Please enter a command: ")
		fmt.Scanln(&input)

		switch input {
		default:
			fmt.Println("unrecognized command")
		case "j":
			fmt.Println("joining quorum")
			q = readQuorumAddresses()
			fmt.Println("connected to quorum")
		case "g":
			fmt.Println("generating Sector")
			s, err = generateSector(q)
			if err != nil {
				fmt.Println("error:", err)
				fmt.Println("failed to generate Sector")
				break
			}
			h = s.Hash
			fmt.Println("created Sector with hash", h[:10])
		case "u":
			fmt.Println("uploading file")
			err = uploadSector(s)
			if err != nil {
				fmt.Println("error:", err)
				fmt.Println("upload failed")
				break
			}
			fmt.Println("upload successful")
		case "d":
			fmt.Println("downloading file")
			rs, err := downloadSector(h)
			if err != nil {
				fmt.Println("error:", err)
				fmt.Println("download failed")
				break
			}
			rh, err := crypto.CalculateHash(rs.Data)
			if err != nil {
				fmt.Println("error:", err)
				break
			}
			fmt.Println("download successful")
			fmt.Println("hash:", rh[:10])
		case "q":
			return
		}
	}
}
Esempio n. 7
0
// TestTCPUploadFile tests the NewTCPServer and UploadFile functions.
// NewTCPServer must properly initialize a TCP server.
// UploadFile must succesfully distribute a file among a quorum.
// The uploaded file must be successfully reconstructed.
func TestTCPUploadFile(t *testing.T) {
	// create TCPServer
	tcp, err := network.NewTCPServer(9988)
	if err != nil {
		t.Fatal("Failed to initialize TCPServer:", err)
	}
	defer tcp.Close()

	// create quorum
	var q [common.QuorumSize]common.Address
	var uhs [common.QuorumSize]uploadHandler
	for i := 0; i < common.QuorumSize; i++ {
		q[i] = common.Address{0, "localhost", 9000 + i}
		qtcp, err := network.NewTCPServer(9000 + i)
		defer qtcp.Close()
		if err != nil {
			t.Fatal("Failed to initialize TCPServer:", err)
		}
		uhs[i].done = make(chan bool, 1)
		q[i].Id = qtcp.AddMessageHandler(&uhs[i]).Id
	}

	// create file
	file, err := os.Create("InputFile")
	if err != nil {
		t.Fatal("Failed to create file \"InputFile\"")
	}
	defer file.Close()
	defer os.Remove("InputFile")

	fileData, err := crypto.RandomByteSlice(70000)
	if err != nil {
		t.Fatal("Could not generate test data:", err)
	}

	err = ioutil.WriteFile("InputFile", fileData, 0644)
	if err != nil {
		t.Fatal("Failed to write to file InputFile:", err)
	}

	// calculate hash
	origHash, err := crypto.CalculateHash(fileData)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	// upload file to quorum
	k := 50
	b, err := UploadFile(tcp, file, k, q)
	if err != nil {
		t.Fatal("Failed to upload file:", err)
	}

	// wait for all participants to complete
	for i := range uhs {
		<-uhs[i].done
	}

	// rebuild file from first k segments
	segments := make([]string, k)
	indices := make([]uint8, k)
	for i := 0; i < k; i++ {
		segments[i] = string(uhs[i].data)
		indices[i] = uint8(uhs[i].index)
	}

	rebuiltData, err := erasure.RebuildSector(k, b, segments, indices)
	if err != nil {
		t.Fatal("Failed to rebuild file:", err)
	}
	// remove padding
	rebuiltData = rebuiltData[:len(fileData)]

	// check hash
	rebuiltHash, err := crypto.CalculateHash(rebuiltData)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	if origHash != rebuiltHash {
		t.Fatal("Failed to recover file: hashes do not match")
	}
}
Esempio n. 8
0
// NewTCPServer must properly initialize a TCP server.
// DownloadFile must successfully retrieve a file from a quorum.
// The downloaded file must match the original file.
func TestTCPDownloadFile(t *testing.T) {
	t.Skip()
	// create file
	fileData, err := crypto.RandomByteSlice(70000)
	if err != nil {
		t.Fatal("Could not generate test data:", err)
	}

	// calculate hash
	origHash, err := crypto.CalculateHash(fileData)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	// encode file
	k := 50
	bytesPerSegment := len(fileData) / k
	if bytesPerSegment%64 != 0 {
		bytesPerSegment += 64 - (bytesPerSegment % 64)
		padding := k*bytesPerSegment - len(fileData)
		fileData = append(fileData, bytes.Repeat([]byte{0x00}, padding)...)
	}
	segments, err := erasure.EncodeRing(k, bytesPerSegment, fileData)
	if err != nil {
		t.Fatal("Failed to encode file data:", err)
	}

	// create TCPServer
	tcp, err := network.NewTCPServer(9988)
	if err != nil {
		t.Fatal("Failed to initialize TCPServer:", err)
	}
	defer tcp.Close()
	tdh := new(downloadHandler)
	tdh.segments = make([]string, k)
	tdh.indices = make([]uint8, k)
	tdh.k, tdh.b = k, bytesPerSegment
	tcp.AddMessageHandler(tdh)

	// create quorum
	var q [common.QuorumSize]common.Address
	var tfhs [common.QuorumSize]TestFileHandler
	for i := 0; i < common.QuorumSize; i++ {
		q[i] = common.Address{0, "localhost", 9000 + i}
		qtcp, err := network.NewTCPServer(9000 + i)
		if err != nil {
			t.Fatal("Failed to initialize TCPServer:", err)
		}
		tfhs[i].tcpServ = qtcp
		tfhs[i].dest = tcp.Address()
		tfhs[i].data = segments[i]
		tfhs[i].done = make(chan bool, 1)
		q[i].Id = qtcp.AddMessageHandler(&tfhs[i]).Id
	}

	// download file from quorum
	downData, err := DownloadFile(tcp, origHash, len(fileData), k, q)
	if err != nil {
		t.Fatal("Failed to download file:", err)
	}

	// wait for download to complete
	<-tdh.done

	// check hash
	rebuiltHash, err := crypto.CalculateHash(downData)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	if origHash != rebuiltHash {
		t.Fatal("Failed to recover file: hashes do not match")
	}
}