@@ -18,9 +18,12 @@ import (
1818 gsnet "github.com/ipfs/go-graphsync/network"
1919 "github.com/ipfs/go-graphsync/storeutil"
2020 bstore "github.com/ipfs/go-ipfs-blockstore"
21+ chunker "github.com/ipfs/go-ipfs-chunker"
2122 offline "github.com/ipfs/go-ipfs-exchange-offline"
2223 ipldformat "github.com/ipfs/go-ipld-format"
2324 "github.com/ipfs/go-merkledag"
25+ "github.com/ipfs/go-unixfs/importer/balanced"
26+ ihelper "github.com/ipfs/go-unixfs/importer/helpers"
2427 "github.com/ipld/go-ipld-prime"
2528 cidlink "github.com/ipld/go-ipld-prime/linking/cid"
2629 "github.com/libp2p/go-libp2p-core/host"
@@ -983,14 +986,19 @@ type retrievalRevalidator struct {
983986 providerPausePoint int
984987 pausePoints []uint64
985988 finalVoucher datatransfer.VoucherResult
989+ revalVouchers []datatransfer.VoucherResult
986990}
987991
988992func (r * retrievalRevalidator ) OnPullDataSent (chid datatransfer.ChannelID , additionalBytesSent uint64 ) (bool , datatransfer.VoucherResult , error ) {
989993 r .dataSoFar += additionalBytesSent
990994 if r .providerPausePoint < len (r .pausePoints ) &&
991995 r .dataSoFar >= r .pausePoints [r .providerPausePoint ] {
996+ var v datatransfer.VoucherResult = testutil .NewFakeDTType ()
997+ if len (r .revalVouchers ) > r .providerPausePoint {
998+ v = r .revalVouchers [r .providerPausePoint ]
999+ }
9921000 r .providerPausePoint ++
993- return true , testutil . NewFakeDTType () , datatransfer .ErrPause
1001+ return true , v , datatransfer .ErrPause
9941002 }
9951003 return true , nil , nil
9961004}
@@ -1098,7 +1106,7 @@ func TestSimulatedRetrievalFlow(t *testing.T) {
10981106 require .NoError (t , dt1 .RegisterVoucherType (& testutil.FakeDTType {}, sv ))
10991107
11001108 srv := & retrievalRevalidator {
1101- testutil .NewStubbedRevalidator (), 0 , 0 , config .pausePoints , finalVoucherResult ,
1109+ testutil .NewStubbedRevalidator (), 0 , 0 , config .pausePoints , finalVoucherResult , []datatransfer. VoucherResult {},
11021110 }
11031111 srv .ExpectSuccessErrResume ()
11041112 require .NoError (t , dt1 .RegisterRevalidator (testutil .NewFakeDTType (), srv ))
@@ -1713,6 +1721,180 @@ func TestRespondingToPullGraphsyncRequests(t *testing.T) {
17131721 }
17141722}
17151723
1724+ // Test the ability to attach data from multiple hooks in the same extension payload by using
1725+ // different names
1726+ func TestMultipleMessagesInExtension (t * testing.T ) {
1727+ pausePoints := []uint64 {1000 , 3000 , 6000 , 10000 , 15000 }
1728+
1729+ ctx , cancel := context .WithTimeout (context .Background (), 4 * time .Second )
1730+ defer cancel ()
1731+
1732+ gsData := testutil .NewGraphsyncTestingData (ctx , t , nil , nil )
1733+ host1 := gsData .Host1 // initiator, data sender
1734+
1735+ root , origBytes := LoadRandomData (ctx , t , gsData .DagService1 )
1736+ gsData .OrigBytes = origBytes
1737+ rootCid := root .(cidlink.Link ).Cid
1738+ tp1 := gsData .SetupGSTransportHost1 ()
1739+ tp2 := gsData .SetupGSTransportHost2 ()
1740+
1741+ dt1 , err := NewDataTransfer (gsData .DtDs1 , gsData .TempDir1 , gsData .DtNet1 , tp1 )
1742+ require .NoError (t , err )
1743+ testutil .StartAndWaitForReady (ctx , t , dt1 )
1744+
1745+ dt2 , err := NewDataTransfer (gsData .DtDs2 , gsData .TempDir2 , gsData .DtNet2 , tp2 )
1746+ require .NoError (t , err )
1747+ testutil .StartAndWaitForReady (ctx , t , dt2 )
1748+
1749+ var chid datatransfer.ChannelID
1750+ errChan := make (chan struct {}, 2 )
1751+
1752+ clientPausePoint := 0
1753+
1754+ clientGotResponse := make (chan struct {}, 1 )
1755+ clientFinished := make (chan struct {}, 1 )
1756+
1757+ // In this retrieval flow we expect 2 voucher results:
1758+ // The first one is sent as a response from the initial request telling the client
1759+ // the provider has accepted the request and is starting to send blocks
1760+ respVoucher := testutil .NewFakeDTType ()
1761+ encodedRVR , err := encoding .Encode (respVoucher )
1762+ require .NoError (t , err )
1763+
1764+ // voucher results are sent by the providers to request payment while pausing until a voucher is sent
1765+ // to revalidate
1766+ voucherResults := []datatransfer.VoucherResult {
1767+ & testutil.FakeDTType {Data : "one" },
1768+ & testutil.FakeDTType {Data : "two" },
1769+ & testutil.FakeDTType {Data : "thr" },
1770+ & testutil.FakeDTType {Data : "for" },
1771+ & testutil.FakeDTType {Data : "fiv" },
1772+ }
1773+
1774+ // The final voucher result is sent by the provider to request a last payment voucher
1775+ finalVoucherResult := testutil .NewFakeDTType ()
1776+ encodedFVR , err := encoding .Encode (finalVoucherResult )
1777+ require .NoError (t , err )
1778+
1779+ dt2 .SubscribeToEvents (func (event datatransfer.Event , channelState datatransfer.ChannelState ) {
1780+ if event .Code == datatransfer .Error {
1781+ errChan <- struct {}{}
1782+ }
1783+ // Here we verify reception of voucherResults by the client
1784+ if event .Code == datatransfer .NewVoucherResult {
1785+ voucherResult := channelState .LastVoucherResult ()
1786+ encodedVR , err := encoding .Encode (voucherResult )
1787+ require .NoError (t , err )
1788+
1789+ // If this voucher result is the response voucher no action is needed
1790+ // we just know that the provider has accepted the transfer and is sending blocks
1791+ if bytes .Equal (encodedVR , encodedRVR ) {
1792+ // The test will fail if no response voucher is received
1793+ clientGotResponse <- struct {}{}
1794+ }
1795+
1796+ // If this voucher is a revalidation request we need to send a new voucher
1797+ // to revalidate and unpause the transfer
1798+ if clientPausePoint < 5 {
1799+ encodedExpected , err := encoding .Encode (voucherResults [clientPausePoint ])
1800+ require .NoError (t , err )
1801+ if bytes .Equal (encodedVR , encodedExpected ) {
1802+ _ = dt2 .SendVoucher (ctx , chid , testutil .NewFakeDTType ())
1803+ clientPausePoint ++
1804+ }
1805+ }
1806+
1807+ // If this voucher result is the final voucher result we need
1808+ // to send a new voucher to unpause the provider and complete the transfer
1809+ if bytes .Equal (encodedVR , encodedFVR ) {
1810+ _ = dt2 .SendVoucher (ctx , chid , testutil .NewFakeDTType ())
1811+ }
1812+ }
1813+
1814+ if channelState .Status () == datatransfer .Completed {
1815+ clientFinished <- struct {}{}
1816+ }
1817+ })
1818+
1819+ providerFinished := make (chan struct {}, 1 )
1820+ dt1 .SubscribeToEvents (func (event datatransfer.Event , channelState datatransfer.ChannelState ) {
1821+ if event .Code == datatransfer .Error {
1822+ errChan <- struct {}{}
1823+ }
1824+ if channelState .Status () == datatransfer .Completed {
1825+ providerFinished <- struct {}{}
1826+ }
1827+ })
1828+
1829+ sv := testutil .NewStubbedValidator ()
1830+ require .NoError (t , dt1 .RegisterVoucherType (& testutil.FakeDTType {}, sv ))
1831+ // Stub in the validator so it returns that exact voucher when calling ValidatePull
1832+ // this validator will not pause transfer when accepting a transfer and will start
1833+ // sending blocks immediately
1834+ sv .StubResult (respVoucher )
1835+
1836+ srv := & retrievalRevalidator {
1837+ testutil .NewStubbedRevalidator (), 0 , 0 , pausePoints , finalVoucherResult , voucherResults ,
1838+ }
1839+ // The stubbed revalidator will authorize Revalidate and return ErrResume to finisht the transfer
1840+ srv .ExpectSuccessErrResume ()
1841+ require .NoError (t , dt1 .RegisterRevalidator (testutil .NewFakeDTType (), srv ))
1842+
1843+ // Register our response voucher with the client
1844+ require .NoError (t , dt2 .RegisterVoucherResultType (respVoucher ))
1845+
1846+ voucher := testutil.FakeDTType {Data : "applesauce" }
1847+ chid , err = dt2 .OpenPullDataChannel (ctx , host1 .ID (), & voucher , rootCid , gsData .AllSelector )
1848+ require .NoError (t , err )
1849+
1850+ // Expect the client to receive a response voucher, the provider to complete the transfer and
1851+ // the client to finish the transfer
1852+ for clientGotResponse != nil || providerFinished != nil || clientFinished != nil {
1853+ select {
1854+ case <- ctx .Done ():
1855+ t .Fatal ("Did not complete successful data transfer" )
1856+ case <- clientGotResponse :
1857+ clientGotResponse = nil
1858+ case <- providerFinished :
1859+ providerFinished = nil
1860+ case <- clientFinished :
1861+ clientFinished = nil
1862+ case <- errChan :
1863+ t .Fatal ("received unexpected error" )
1864+ }
1865+ }
1866+ sv .VerifyExpectations (t )
1867+ srv .VerifyExpectations (t )
1868+ gsData .VerifyFileTransferred (t , root , true )
1869+ }
1870+
1871+ func LoadRandomData (ctx context.Context , t * testing.T , dagService ipldformat.DAGService ) (ipld.Link , []byte ) {
1872+ data := make ([]byte , 256000 )
1873+ rand .New (rand .NewSource (time .Now ().UnixNano ())).Read (data )
1874+
1875+ // import to UnixFS
1876+ bufferedDS := ipldformat .NewBufferedDAG (ctx , dagService )
1877+
1878+ params := ihelper.DagBuilderParams {
1879+ Maxlinks : 1024 ,
1880+ RawLeaves : true ,
1881+ CidBuilder : nil ,
1882+ Dagserv : bufferedDS ,
1883+ }
1884+
1885+ db , err := params .New (chunker .NewSizeSplitter (bytes .NewReader (data ), int64 (1 << 10 )))
1886+ require .NoError (t , err )
1887+
1888+ nd , err := balanced .Layout (db )
1889+ require .NoError (t , err )
1890+
1891+ err = bufferedDS .Commit ()
1892+ require .NoError (t , err )
1893+
1894+ // save the original files bytes
1895+ return cidlink.Link {Cid : nd .Cid ()}, data
1896+ }
1897+
17161898type receivedMessage struct {
17171899 message datatransfer.Message
17181900 sender peer.ID
0 commit comments