// Create and initialize a state object. func CreateState(messageRouter common.MessageRouter) (s *State, err error) { s = new(State) // check that we have a non-nil messageSender if messageRouter == nil { err = fmt.Errorf("Cannot initialize with a nil messageRouter") return } // create a signature keypair for this state pubKey, secKey, err := crypto.CreateKeyPair() if err != nil { return } // calculate the value of an empty hash (default for storedEntropyStage2 on all hosts is a blank array) emptyHash, err := crypto.CalculateTruncatedHash(s.storedEntropyStage2[:]) if err != nil { return } // set state variables to their defaults s.messageRouter = messageRouter s.self = new(participant) s.self.address = messageRouter.AddMessageHandler(s) s.self.publicKey = pubKey s.secretKey = secKey for i := range s.previousEntropyStage1 { s.previousEntropyStage1[i] = emptyHash } s.participantIndex = 255 s.currentStep = 1 s.wallets = make(map[string]uint64) return }
// Create and initialize a state object. Set everything to default. func CreateState(messageRouter common.MessageRouter) (s *State, err error) { // check that we have a non-nil messageSender if messageRouter == nil { err = fmt.Errorf("Cannot initialize with a nil messageRouter") return } // create a signature keypair for this state pubKey, secKey, err := crypto.CreateKeyPair() if err != nil { return } // initialize State with default values and keypair s = &State{ messageRouter: messageRouter, self: &Participant{ index: 255, address: messageRouter.Address(), publicKey: pubKey, }, secretKey: secKey, currentStep: 1, } // register State and store our assigned ID s.self.address.ID = messageRouter.RegisterHandler(s) // a call to joinSia() may be placed here... behavior not fully defined return }
// DownloadFile retrieves the erasure-coded segments corresponding to a given file from a quorum. // It reconstructs the original file from the segments using erasure.RebuildSector(). func DownloadFile(mr common.MessageRouter, fileHash crypto.Hash, length int, k int, quorum [common.QuorumSize]common.Address) (fileData []byte, err error) { // spawn a separate thread for each segment for i := range quorum { go func() { // send request m := new(common.Message) m.Destination = quorum[i] m.Payload = []byte{0x01} m.Payload = append(m.Payload, fileHash[:]...) mr.SendMessage(m) // wait for response }() } return }
// TestTCPDownloadFile tests the NewTCPServer and DownloadFile functions. // NewTCPServer must properly initialize a TCP server. // UploadFile splits a file into erasure-coded segments and distributes them across a quorum. // k is the number of non-redundant segments. // The file is padded to satisfy the erasure-coding requirements that: // len(fileData) = k*bytesPerSegment, and: // bytesPerSegment % 64 = 0 func UploadFile(mr common.MessageRouter, file *os.File, k int, quorum [common.QuorumSize]common.Address) (bytesPerSegment int, err error) { // read file fileInfo, err := file.Stat() if err != nil { return } if fileInfo.Size() > int64(common.QuorumSize*common.MaxSegmentSize) { err = fmt.Errorf("File exceeds maximum per-quorum size") return } fileData := make([]byte, fileInfo.Size()) _, err = io.ReadFull(file, fileData) if err != nil { return } // calculate EncodeRing parameters, padding file if necessary 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)...) } // create erasure-coded segments segments, err := erasure.EncodeRing(k, bytesPerSegment, fileData) if err != nil { return } // for now we just send segment i to node i // this may need to be randomized for security for i := range quorum { m := new(common.Message) m.Destination = quorum[i] m.Payload = append([]byte{byte(i)}, []byte(segments[i])...) err = mr.SendMessage(m) if err != nil { return } } return }