@@ -18,9 +18,12 @@ import (
18
18
gsnet "github.com/ipfs/go-graphsync/network"
19
19
"github.com/ipfs/go-graphsync/storeutil"
20
20
bstore "github.com/ipfs/go-ipfs-blockstore"
21
+ chunker "github.com/ipfs/go-ipfs-chunker"
21
22
offline "github.com/ipfs/go-ipfs-exchange-offline"
22
23
ipldformat "github.com/ipfs/go-ipld-format"
23
24
"github.com/ipfs/go-merkledag"
25
+ "github.com/ipfs/go-unixfs/importer/balanced"
26
+ ihelper "github.com/ipfs/go-unixfs/importer/helpers"
24
27
"github.com/ipld/go-ipld-prime"
25
28
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
26
29
"github.com/libp2p/go-libp2p-core/host"
@@ -983,14 +986,19 @@ type retrievalRevalidator struct {
983
986
providerPausePoint int
984
987
pausePoints []uint64
985
988
finalVoucher datatransfer.VoucherResult
989
+ revalVouchers []datatransfer.VoucherResult
986
990
}
987
991
988
992
func (r * retrievalRevalidator ) OnPullDataSent (chid datatransfer.ChannelID , additionalBytesSent uint64 ) (bool , datatransfer.VoucherResult , error ) {
989
993
r .dataSoFar += additionalBytesSent
990
994
if r .providerPausePoint < len (r .pausePoints ) &&
991
995
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
+ }
992
1000
r .providerPausePoint ++
993
- return true , testutil . NewFakeDTType () , datatransfer .ErrPause
1001
+ return true , v , datatransfer .ErrPause
994
1002
}
995
1003
return true , nil , nil
996
1004
}
@@ -1098,7 +1106,7 @@ func TestSimulatedRetrievalFlow(t *testing.T) {
1098
1106
require .NoError (t , dt1 .RegisterVoucherType (& testutil.FakeDTType {}, sv ))
1099
1107
1100
1108
srv := & retrievalRevalidator {
1101
- testutil .NewStubbedRevalidator (), 0 , 0 , config .pausePoints , finalVoucherResult ,
1109
+ testutil .NewStubbedRevalidator (), 0 , 0 , config .pausePoints , finalVoucherResult , []datatransfer. VoucherResult {},
1102
1110
}
1103
1111
srv .ExpectSuccessErrResume ()
1104
1112
require .NoError (t , dt1 .RegisterRevalidator (testutil .NewFakeDTType (), srv ))
@@ -1713,6 +1721,180 @@ func TestRespondingToPullGraphsyncRequests(t *testing.T) {
1713
1721
}
1714
1722
}
1715
1723
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
+
1716
1898
type receivedMessage struct {
1717
1899
message datatransfer.Message
1718
1900
sender peer.ID
0 commit comments