當前位置: 首頁>>代碼示例>>Golang>>正文


Golang encoding.ReadObject函數代碼示例

本文整理匯總了Golang中github.com/NebulousLabs/Sia/encoding.ReadObject函數的典型用法代碼示例。如果您正苦於以下問題:Golang ReadObject函數的具體用法?Golang ReadObject怎麽用?Golang ReadObject使用的例子?那麽, 這裏精選的函數代碼示例或許可以為您提供幫助。


在下文中一共展示了ReadObject函數的15個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。

示例1: TestShareNodes

func TestShareNodes(t *testing.T) {
	g1 := newTestingGateway("TestShareNodes1", t)
	defer g1.Close()
	g2 := newTestingGateway("TestShareNodes2", t)
	defer g2.Close()

	// add a node to g2
	id := g2.mu.Lock()
	g2.addNode(dummyNode)
	g2.mu.Unlock(id)

	// connect
	err := g1.Connect(g2.Address())
	if err != nil {
		t.Fatal("couldn't connect:", err)
	}

	// g1 should have received the node
	time.Sleep(100 * time.Millisecond)
	id = g1.mu.Lock()
	if g1.addNode(dummyNode) == nil {
		t.Fatal("gateway did not receive nodes during Connect:", g1.nodes)
	}
	g1.mu.Unlock(id)

	// remove all nodes from both peers
	id = g1.mu.Lock()
	g1.nodes = map[modules.NetAddress]struct{}{}
	g1.mu.Unlock(id)
	id = g2.mu.Lock()
	g2.nodes = map[modules.NetAddress]struct{}{}
	g2.mu.Unlock(id)

	// SharePeers should now return no peers
	var nodes []modules.NetAddress
	err = g1.RPC(g2.Address(), "ShareNodes", func(conn modules.PeerConn) error {
		return encoding.ReadObject(conn, &nodes, maxSharedNodes*maxAddrLength)
	})
	if err != nil {
		t.Fatal(err)
	}
	if len(nodes) != 0 {
		t.Fatal("gateway gave non-existent addresses:", nodes)
	}

	// sharing should be capped at maxSharedNodes
	for i := 0; i < maxSharedNodes+10; i++ {
		g2.addNode(modules.NetAddress("111.111.111.111:" + strconv.Itoa(i)))
	}
	err = g1.RPC(g2.Address(), "ShareNodes", func(conn modules.PeerConn) error {
		return encoding.ReadObject(conn, &nodes, maxSharedNodes*maxAddrLength)
	})
	if err != nil {
		t.Fatal(err)
	}
	if len(nodes) != maxSharedNodes {
		t.Fatalf("gateway gave wrong number of nodes: expected %v, got %v", maxSharedNodes, len(nodes))
	}
}
開發者ID:kustomzone,項目名稱:Sia,代碼行數:59,代碼來源:nodes_test.go

示例2: receiveBlocks

// receiveBlocks is the calling end of the SendBlocks RPC.
func (s *ConsensusSet) receiveBlocks(conn modules.PeerConn) error {
	// get blockIDs to send
	lockID := s.mu.RLock()
	if !s.db.open {
		s.mu.RUnlock(lockID)
		return errors.New("database not open")
	}
	history := s.blockHistory()
	s.mu.RUnlock(lockID)
	if err := encoding.WriteObject(conn, history); err != nil {
		return err
	}

	// loop until no more blocks are available
	moreAvailable := true
	for moreAvailable {
		var newBlocks []types.Block
		if err := encoding.ReadObject(conn, &newBlocks, MaxCatchUpBlocks*types.BlockSizeLimit); err != nil {
			return err
		}
		if err := encoding.ReadObject(conn, &moreAvailable, 1); err != nil {
			return err
		}

		// integrate received blocks.
		for _, block := range newBlocks {
			// Blocks received during synchronize aren't trusted; activate full
			// verification.
			lockID := s.mu.Lock()
			if !s.db.open {
				s.mu.Unlock(lockID)
				return errors.New("database not open")
			}
			acceptErr := s.acceptBlock(block)
			s.mu.Unlock(lockID)
			// ErrNonExtendingBlock must be ignored until headers-first block
			// sharing is implemented.
			if acceptErr == modules.ErrNonExtendingBlock {
				acceptErr = nil
			}
			if acceptErr != nil {
				return acceptErr
			}

			// Yield the processor to give other processes time to grab a lock.
			// The Lock/Unlock cycle in this loop is very tight, and has been
			// known to prevent interrupts from getting lock access quickly.
			runtime.Gosched()
		}
	}

	return nil
}
開發者ID:kustomzone,項目名稱:Sia,代碼行數:54,代碼來源:synchronize.go

示例3: managedRPCRecentRevision

// managedRPCRecentRevision sends the most recent known file contract
// revision, including signatures, to the renter, for the file contract with
// the input id.
func (h *Host) managedRPCRecentRevision(conn net.Conn) (types.FileContractID, *storageObligation, error) {
	// Set the negotiation deadline.
	conn.SetDeadline(time.Now().Add(modules.NegotiateRecentRevisionTime))

	// Receive the file contract id from the renter.
	var fcid types.FileContractID
	err := encoding.ReadObject(conn, &fcid, uint64(len(fcid)))
	if err != nil {
		return types.FileContractID{}, nil, err
	}

	// Send a challenge to the renter to verify that the renter has write
	// access to the revision being opened.
	var challenge crypto.Hash
	_, err = rand.Read(challenge[:])
	if err != nil {
		return types.FileContractID{}, nil, err
	}
	err = encoding.WriteObject(conn, challenge)
	if err != nil {
		return types.FileContractID{}, nil, err
	}

	// Read the signed response from the renter.
	var challengeResponse crypto.Signature
	err = encoding.ReadObject(conn, &challengeResponse, uint64(len(challengeResponse)))
	if err != nil {
		return types.FileContractID{}, nil, err
	}
	// Verify the response. In the process, fetch the related storage
	// obligation, file contract revision, and transaction signatures.
	so, recentRevision, revisionSigs, err := h.verifyChallengeResponse(fcid, challenge, challengeResponse)
	if err != nil {
		return types.FileContractID{}, nil, modules.WriteNegotiationRejection(conn, err)
	}

	// Send the file contract revision and the corresponding signatures to the
	// renter.
	err = modules.WriteNegotiationAcceptance(conn)
	if err != nil {
		return types.FileContractID{}, nil, err
	}
	err = encoding.WriteObject(conn, recentRevision)
	if err != nil {
		return types.FileContractID{}, nil, err
	}
	err = encoding.WriteObject(conn, revisionSigs)
	if err != nil {
		return types.FileContractID{}, nil, err
	}
	return fcid, so, nil
}
開發者ID:CSSZiegler,項目名稱:Sia,代碼行數:55,代碼來源:negotiaterecentrevision.go

示例4: negotiateRevision

// negotiateRevision sends the revision and new piece data to the host.
func negotiateRevision(conn net.Conn, rev types.FileContractRevision, piece []byte, secretKey crypto.SecretKey) (types.Transaction, error) {
	conn.SetDeadline(time.Now().Add(5 * time.Minute)) // sufficient to transfer 4 MB over 100 kbps
	defer conn.SetDeadline(time.Time{})               // reset timeout after each revision

	// create transaction containing the revision
	signedTxn := types.Transaction{
		FileContractRevisions: []types.FileContractRevision{rev},
		TransactionSignatures: []types.TransactionSignature{{
			ParentID:       crypto.Hash(rev.ParentID),
			CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
			PublicKeyIndex: 0, // renter key is always first -- see negotiateContract
		}},
	}
	// sign the transaction
	encodedSig, _ := crypto.SignHash(signedTxn.SigHash(0), secretKey) // no error possible
	signedTxn.TransactionSignatures[0].Signature = encodedSig[:]

	// send the transaction
	if err := encoding.WriteObject(conn, signedTxn); err != nil {
		return types.Transaction{}, errors.New("couldn't send revision transaction: " + err.Error())
	}

	// host sends acceptance
	var response string
	if err := encoding.ReadObject(conn, &response, 128); err != nil {
		return types.Transaction{}, errors.New("couldn't read host acceptance: " + err.Error())
	}
	if response != modules.AcceptResponse {
		return types.Transaction{}, errors.New("host rejected revision: " + response)
	}

	// transfer piece
	if _, err := conn.Write(piece); err != nil {
		return types.Transaction{}, errors.New("couldn't transfer piece: " + err.Error())
	}

	// read txn signed by host
	var signedHostTxn types.Transaction
	if err := encoding.ReadObject(conn, &signedHostTxn, types.BlockSizeLimit); err != nil {
		return types.Transaction{}, errors.New("couldn't read signed revision transaction: " + err.Error())
	}

	if signedHostTxn.ID() != signedTxn.ID() {
		return types.Transaction{}, errors.New("host sent bad signed transaction")
	}

	return signedHostTxn, nil
}
開發者ID:zzmjohn,項目名稱:Sia,代碼行數:49,代碼來源:negotiate.go

示例5: TestNegotiateRevisionStopResponse

// TestNegotiateRevisionStopResponse tests that when the host sends
// StopResponse, the renter continues processing the revision instead of
// immediately terminating.
func TestNegotiateRevisionStopResponse(t *testing.T) {
	// simulate a renter-host connection
	rConn, hConn := net.Pipe()

	// handle the host's half of the pipe
	go func() {
		defer hConn.Close()
		// read revision
		encoding.ReadObject(hConn, new(types.FileContractRevision), 1<<22)
		// write acceptance
		modules.WriteNegotiationAcceptance(hConn)
		// read txn signature
		encoding.ReadObject(hConn, new(types.TransactionSignature), 1<<22)
		// write StopResponse
		modules.WriteNegotiationStop(hConn)
		// write txn signature
		encoding.WriteObject(hConn, types.TransactionSignature{})
	}()

	// since the host wrote StopResponse, we should proceed to validating the
	// transaction. This will return a known error because we are supplying an
	// empty revision.
	_, err := negotiateRevision(rConn, types.FileContractRevision{}, crypto.SecretKey{})
	if err != types.ErrFileContractWindowStartViolation {
		t.Fatalf("expected %q, got \"%v\"", types.ErrFileContractWindowStartViolation, err)
	}
	rConn.Close()

	// same as above, but send an error instead of StopResponse. The error
	// should be returned by negotiateRevision immediately (if it is not, we
	// should expect to see a transaction validation error instead).
	rConn, hConn = net.Pipe()
	go func() {
		defer hConn.Close()
		encoding.ReadObject(hConn, new(types.FileContractRevision), 1<<22)
		modules.WriteNegotiationAcceptance(hConn)
		encoding.ReadObject(hConn, new(types.TransactionSignature), 1<<22)
		// write a sentinel error
		modules.WriteNegotiationRejection(hConn, errors.New("sentinel"))
		encoding.WriteObject(hConn, types.TransactionSignature{})
	}()
	expectedErr := "host did not accept transaction signature: sentinel"
	_, err = negotiateRevision(rConn, types.FileContractRevision{}, crypto.SecretKey{})
	if err == nil || err.Error() != expectedErr {
		t.Fatalf("expected %q, got \"%v\"", expectedErr, err)
	}
	rConn.Close()
}
開發者ID:robvanmieghem,項目名稱:Sia,代碼行數:51,代碼來源:negotiate_test.go

示例6: rpcSendBlk

// rpcSendBlk is an RPC that sends the requested block to the requesting peer.
func (cs *ConsensusSet) rpcSendBlk(conn modules.PeerConn) error {
	err := cs.tg.Add()
	if err != nil {
		return err
	}
	defer cs.tg.Done()

	// Decode the block id from the connection.
	var id types.BlockID
	err = encoding.ReadObject(conn, &id, crypto.HashSize)
	if err != nil {
		return err
	}
	// Lookup the corresponding block.
	var b types.Block
	cs.mu.RLock()
	err = cs.db.View(func(tx *bolt.Tx) error {
		pb, err := getBlockMap(tx, id)
		if err != nil {
			return err
		}
		b = pb.Block
		return nil
	})
	cs.mu.RUnlock()
	if err != nil {
		return err
	}
	// Encode and send the block to the caller.
	err = encoding.WriteObject(conn, b)
	if err != nil {
		return err
	}
	return nil
}
開發者ID:robvanmieghem,項目名稱:Sia,代碼行數:36,代碼來源:synchronize.go

示例7: handleConn

// TODO: maintain compatibility
func (h *Host) handleConn(conn net.Conn) {
	defer conn.Close()
	// Set an initial duration that is generous, but finite. RPCs can extend
	// this if so desired.
	conn.SetDeadline(time.Now().Add(5 * time.Minute))

	var id types.Specifier
	if err := encoding.ReadObject(conn, &id, 16); err != nil {
		return
	}
	var err error
	switch id {
	case modules.RPCSettings:
		err = h.rpcSettings(conn)
	case modules.RPCUpload:
		err = h.rpcUpload(conn)
	case modules.RPCRevise:
		err = h.rpcRevise(conn)
	case modules.RPCDownload:
		err = h.rpcDownload(conn)
	default:
		h.log.Printf("WARN: incoming conn %v requested unknown RPC \"%v\"", conn.RemoteAddr(), id)
		return
	}
	if err != nil {
		h.log.Printf("WARN: incoming RPC \"%v\" failed: %v", id, err)
	}
}
開發者ID:mantyr,項目名稱:Sia,代碼行數:29,代碼來源:net.go

示例8: threadedHandleConn

// threadedHandleConn reads header data from a connection, then routes it to the
// appropriate handler for further processing.
func (g *Gateway) threadedHandleConn(conn modules.PeerConn) {
	defer conn.Close()
	var id rpcID
	if err := encoding.ReadObject(conn, &id, 8); err != nil {
		return
	}
	// call registered handler for this ID
	lockid := g.mu.RLock()
	fn, ok := g.handlers[id]
	g.mu.RUnlock(lockid)
	if !ok {
		g.log.Printf("WARN: incoming conn %v requested unknown RPC \"%v\"", conn.RemoteAddr(), id)
		return
	}

	// call fn
	err := fn(conn)
	// don't log benign errors
	if err == modules.ErrDuplicateTransactionSet || err == modules.ErrBlockKnown {
		err = nil
	}
	if err != nil {
		g.log.Printf("WARN: incoming RPC \"%v\" failed: %v", id, err)
	}
}
開發者ID:pcoindev,項目名稱:Sia,代碼行數:27,代碼來源:rpc.go

示例9: rpcRetrieve

// rpcRetrieve is an RPC that uploads a specified file to a client.
//
// Mutexes are applied carefully to avoid locking during I/O. All necessary
// interaction with the host involves looking up the filepath of the file being
// requested. This is done all at once.
func (h *Host) rpcRetrieve(conn net.Conn) error {
	// Get the filename.
	var contractID types.FileContractID
	err := encoding.ReadObject(conn, &contractID, crypto.HashSize)
	if err != nil {
		return err
	}

	// Verify the file exists, using a mutex while reading the host.
	lockID := h.mu.RLock()
	contractObligation, exists := h.obligationsByID[contractID]
	if !exists {
		h.mu.RUnlock(lockID)
		return errors.New("no record of that file")
	}
	path := filepath.Join(h.saveDir, contractObligation.Path)
	h.mu.RUnlock(lockID)

	// Open the file.
	file, err := os.Open(path)
	if err != nil {
		return err
	}
	defer file.Close()

	// Transmit the file.
	_, err = io.CopyN(conn, file, int64(contractObligation.FileContract.FileSize))
	if err != nil {
		return err
	}

	return nil
}
開發者ID:mm3,項目名稱:Sia,代碼行數:38,代碼來源:upload.go

示例10: rpcRelayBlock

// rpcRelayBlock is an RPC that accepts a block from a peer.
// COMPATv0.5.1
func (cs *ConsensusSet) rpcRelayBlock(conn modules.PeerConn) error {
	err := cs.tg.Add()
	if err != nil {
		return err
	}
	defer cs.tg.Done()

	// Decode the block from the connection.
	var b types.Block
	err = encoding.ReadObject(conn, &b, types.BlockSizeLimit)
	if err != nil {
		return err
	}

	// Submit the block to the consensus set and broadcast it.
	err = cs.managedAcceptBlock(b)
	if err == errOrphan {
		// If the block is an orphan, try to find the parents. The block
		// received from the peer is discarded and will be downloaded again if
		// the parent is found.
		go func() {
			err := cs.gateway.RPC(conn.RPCAddr(), "SendBlocks", cs.managedReceiveBlocks)
			if err != nil {
				cs.log.Debugln("WARN: failed to get parents of orphan block:", err)
			}
		}()
	}
	if err != nil {
		return err
	}
	cs.managedBroadcastBlock(b)
	return nil
}
開發者ID:robvanmieghem,項目名稱:Sia,代碼行數:35,代碼來源:synchronize.go

示例11: rpcDownload

// rpcDownload is an RPC that uploads requested segments of a file. After the
// RPC has been initiated, the host will read and process requests in a loop
// until the 'stop' signal is received or the connection times out.
func (h *Host) rpcDownload(conn net.Conn) error {
	// Read the contract ID.
	var contractID types.FileContractID
	err := encoding.ReadObject(conn, &contractID, crypto.HashSize)
	if err != nil {
		return err
	}

	// Verify the file exists, using a mutex while reading the host.
	h.mu.RLock()
	co, exists := h.obligationsByID[contractID]
	if !exists {
		h.mu.RUnlock()
		return errors.New("no record of that file")
	}
	h.mu.RUnlock()

	// Open the file.
	file, err := os.Open(co.Path)
	if err != nil {
		return err
	}
	defer file.Close()

	// Process requests until 'stop' signal is received.
	var request modules.DownloadRequest
	for {
		if err := encoding.ReadObject(conn, &request, 16); err != nil {
			return err
		}
		// Check for termination signal.
		// TODO: perform other sanity checks on offset/length?
		if request.Length == 0 {
			break
		}

		conn.SetDeadline(time.Now().Add(5 * time.Minute)) // sufficient to transfer 4 MB over 100 kbps

		// Write segment to conn.
		segment := io.NewSectionReader(file, int64(request.Offset), int64(request.Length))
		_, err := io.Copy(conn, segment)
		if err != nil {
			return err
		}
	}
	return nil
}
開發者ID:mantyr,項目名稱:Sia,代碼行數:50,代碼來源:upload.go

示例12: acceptConn

// acceptConn adds a connecting node as a peer.
func (g *Gateway) acceptConn(conn net.Conn) {
	addr := modules.NetAddress(conn.RemoteAddr().String())
	g.log.Printf("INFO: %v wants to connect", addr)

	// read version
	var remoteVersion string
	if err := encoding.ReadObject(conn, &remoteVersion, maxAddrLength); err != nil {
		conn.Close()
		g.log.Printf("INFO: %v wanted to connect, but we could not read their version: %v", addr, err)
		return
	}

	// check that version is acceptable
	// NOTE: this version must be bumped whenever the gateway or consensus
	// breaks compatibility.
	if build.VersionCmp(remoteVersion, "0.3.3") < 0 {
		encoding.WriteObject(conn, "reject")
		conn.Close()
		g.log.Printf("INFO: %v wanted to connect, but their version (%v) was unacceptable", addr, remoteVersion)
		return
	}

	// respond with our version
	if err := encoding.WriteObject(conn, build.Version); err != nil {
		conn.Close()
		g.log.Printf("INFO: could not write version ack to %v: %v", addr, err)
		return
	}

	// If we are already fully connected, kick out an old peer to make room
	// for the new one. Importantly, prioritize kicking a peer with the same
	// IP as the connecting peer. This protects against Sybil attacks.
	id := g.mu.Lock()
	if len(g.peers) >= fullyConnectedThreshold {
		// first choose a random peer, preferably inbound. If have only
		// outbound peers, we'll wind up kicking an outbound peer; but
		// subsequent inbound connections will kick each other instead of
		// continuing to replace outbound peers.
		kick, err := g.randomInboundPeer()
		if err != nil {
			kick, _ = g.randomPeer()
		}
		// if another peer shares this IP, choose that one instead
		for p := range g.peers {
			if p.Host() == addr.Host() {
				kick = p
				break
			}
		}
		g.peers[kick].sess.Close()
		delete(g.peers, kick)
		g.log.Printf("INFO: disconnected from %v to make room for %v", kick, addr)
	}
	// add the peer
	g.addPeer(&peer{addr: addr, sess: muxado.Server(conn), inbound: true})
	g.mu.Unlock(id)

	g.log.Printf("INFO: accepted connection from new peer %v (v%v)", addr, remoteVersion)
}
開發者ID:xmagicbox,項目名稱:Sia,代碼行數:60,代碼來源:peers.go

示例13: relayTransactionSet

// relayTransactionSet is an RPC that accepts a transaction set from a peer. If
// the accept is successful, the transaction will be relayed to the gateway's
// other peers.
func (tp *TransactionPool) relayTransactionSet(conn modules.PeerConn) error {
	var ts []types.Transaction
	err := encoding.ReadObject(conn, &ts, types.BlockSizeLimit)
	if err != nil {
		return err
	}
	return tp.AcceptTransactionSet(ts)
}
開發者ID:pcoindev,項目名稱:Sia,代碼行數:11,代碼來源:accept.go

示例14: threadedReceiveBlocks

// threadedReceiveBlocks is the calling end of the SendBlocks RPC.
func (cs *ConsensusSet) threadedReceiveBlocks(conn modules.PeerConn) error {
	// Get blockIDs to send.
	var history [32]types.BlockID
	err := cs.db.View(func(tx *bolt.Tx) error {
		history = blockHistory(tx)
		return nil
	})
	if err != nil {
		return err
	}

	// Send the block ids.
	if err := encoding.WriteObject(conn, history); err != nil {
		return err
	}

	// Read blocks off of the wire and add them to the consensus set until
	// there are no more blocks available.
	moreAvailable := true
	for moreAvailable {
		// Read a slice of blocks from the wire.
		var newBlocks []types.Block
		if err := encoding.ReadObject(conn, &newBlocks, MaxCatchUpBlocks*types.BlockSizeLimit); err != nil {
			return err
		}
		if err := encoding.ReadObject(conn, &moreAvailable, 1); err != nil {
			return err
		}

		// Integrate the blocks into the consensus set.
		for _, block := range newBlocks {
			acceptErr := cs.AcceptBlock(block)

			// ErrNonExtendingBlock must be ignored until headers-first block
			// sharing is implemented, block already in database should also be
			// ignored.
			if acceptErr == modules.ErrNonExtendingBlock || acceptErr == modules.ErrBlockKnown {
				acceptErr = nil
			}
			if acceptErr != nil {
				return acceptErr
			}
		}
	}
	return nil
}
開發者ID:cfromknecht,項目名稱:Sia,代碼行數:47,代碼來源:synchronize.go

示例15: managedRPCRenew

// managedRPCRenew is an RPC that allows a renter to renew a file contract. The
// protocol is identical to standard contract negotiation, except that the
// Merkle root is copied over from the old contract.
func (h *Host) managedRPCRenew(conn net.Conn) error {
	// Terminate connection if host is not accepting contracts.
	h.mu.RLock()
	accepting := h.settings.AcceptingContracts
	h.mu.RUnlock()
	if !accepting {
		return nil
	}

	// read ID of contract to be renewed
	var fcid types.FileContractID
	if err := encoding.ReadObject(conn, &fcid, crypto.HashSize); err != nil {
		return errors.New("couldn't read contract ID: " + err.Error())
	}

	h.mu.RLock()
	obligation, exists := h.obligationsByID[fcid]
	h.mu.RUnlock()
	if !exists {
		return errors.New("no record of that contract")
	}
	// need to protect against simultaneous renewals of the same contract
	obligation.mu.Lock()
	defer obligation.mu.Unlock()

	// copy over old file data
	h.mu.RLock()
	h.fileCounter++
	filename := filepath.Join(h.persistDir, strconv.Itoa(int(h.fileCounter)))
	h.mu.RUnlock()

	// TODO: What happens if the copy operation fails partway through? Does
	// there need to be garbage collection at startup for failed uploads that
	// might still be on disk?
	old, err := os.Open(obligation.Path)
	if err != nil {
		return err
	}
	renewed, err := os.Create(filename)
	if err != nil {
		return err
	}
	_, err = io.Copy(renewed, old)
	if err != nil {
		return err
	}

	err = h.managedNegotiateContract(conn, obligation.fileSize(), obligation.merkleRoot(), filename)
	if err != nil {
		// Negotiation failed, delete the copied file.
		err2 := os.Remove(filename)
		if err2 != nil {
			return errors.New(err.Error() + " and " + err2.Error())
		}
		return err
	}
	return nil
}
開發者ID:zzmjohn,項目名稱:Sia,代碼行數:61,代碼來源:upload.go


注:本文中的github.com/NebulousLabs/Sia/encoding.ReadObject函數示例由純淨天空整理自Github/MSDocs等開源代碼及文檔管理平台,相關代碼片段篩選自各路編程大神貢獻的開源項目,源碼版權歸原作者所有,傳播和使用請參考對應項目的License;未經允許,請勿轉載。