Skip to content
This repository was archived by the owner on Aug 2, 2021. It is now read-only.

Commit b635061

Browse files
jmozahacud
authored andcommitted
api, chunk, cmd, shed, storage: add support for pinning content (#1509)
* add support for pinning content as per the specifications defined initially in #1274 and as further discussed in https://swarmresear.ch/t/pinned-content-in-swarm
1 parent c099733 commit b635061

39 files changed

+1648
-143
lines changed

api/api.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,19 @@ package api
2121

2222
import (
2323
"archive/tar"
24+
"bytes"
2425
"context"
2526
"crypto/ecdsa"
2627
"encoding/hex"
2728
"errors"
2829
"fmt"
2930
"io"
3031
"math/big"
32+
"mime"
3133
"net/http"
3234
"path"
33-
"strings"
34-
35-
"bytes"
36-
"mime"
3735
"path/filepath"
36+
"strings"
3837
"time"
3938

4039
"github.com/ethereum/go-ethereum/common"
@@ -47,8 +46,7 @@ import (
4746
"github.com/ethersphere/swarm/storage"
4847
"github.com/ethersphere/swarm/storage/feed"
4948
"github.com/ethersphere/swarm/storage/feed/lookup"
50-
51-
opentracing "github.com/opentracing/opentracing-go"
49+
"github.com/opentracing/opentracing-go"
5250
)
5351

5452
var (
@@ -400,6 +398,8 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage
400398
return
401399
}
402400

401+
// Delete handles removing a file from the manifest.
402+
// This creates a new manifest without the given path
403403
func (a *API) Delete(ctx context.Context, addr string, path string) (storage.Address, error) {
404404
apiDeleteCount.Inc(1)
405405
uri, err := Parse("bzz:/" + addr)

api/client/client.go

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type Client struct {
6363

6464
// UploadRaw uploads raw data to swarm and returns the resulting hash. If toEncrypt is true it
6565
// uploads encrypted data
66-
func (c *Client) UploadRaw(r io.Reader, size int64, toEncrypt bool) (string, error) {
66+
func (c *Client) UploadRaw(r io.Reader, size int64, toEncrypt bool, toPin bool) (string, error) {
6767
if size <= 0 {
6868
return "", errors.New("data size must be greater than zero")
6969
}
@@ -78,6 +78,11 @@ func (c *Client) UploadRaw(r io.Reader, size int64, toEncrypt bool) (string, err
7878
req.ContentLength = size
7979
req.Header.Set(swarmhttp.SwarmTagHeaderName, fmt.Sprintf("raw_upload_%d", time.Now().Unix()))
8080

81+
// Set the pinning header if the file needs to be pinned
82+
if toPin {
83+
req.Header.Set(swarmhttp.PinHeaderName, "true")
84+
}
85+
8186
res, err := http.DefaultClient.Do(req)
8287
if err != nil {
8388
return "", err
@@ -151,11 +156,11 @@ func Open(path string) (*File, error) {
151156
// (if the manifest argument is non-empty) or creates a new manifest containing
152157
// the file, returning the resulting manifest hash (the file will then be
153158
// available at bzz:/<hash>/<path>)
154-
func (c *Client) Upload(file *File, manifest string, toEncrypt bool) (string, error) {
159+
func (c *Client) Upload(file *File, manifest string, toEncrypt bool, toPin bool) (string, error) {
155160
if file.Size <= 0 {
156161
return "", errors.New("file size must be greater than zero")
157162
}
158-
return c.TarUpload(manifest, &FileUploader{file}, "", toEncrypt)
163+
return c.TarUpload(manifest, &FileUploader{file}, "", toEncrypt, toPin)
159164
}
160165

161166
// Download downloads a file with the given path from the swarm manifest with
@@ -185,7 +190,7 @@ func (c *Client) Download(hash, path string) (*File, error) {
185190
// directory will then be available at bzz:/<hash>/path/to/file), with
186191
// the file specified in defaultPath being uploaded to the root of the manifest
187192
// (i.e. bzz:/<hash>/)
188-
func (c *Client) UploadDirectory(dir, defaultPath, manifest string, toEncrypt bool) (string, error) {
193+
func (c *Client) UploadDirectory(dir, defaultPath, manifest string, toEncrypt bool, toPin bool) (string, error) {
189194
stat, err := os.Stat(dir)
190195
if err != nil {
191196
return "", err
@@ -200,7 +205,7 @@ func (c *Client) UploadDirectory(dir, defaultPath, manifest string, toEncrypt bo
200205
return "", fmt.Errorf("default path: %v", err)
201206
}
202207
}
203-
return c.TarUpload(manifest, &DirectoryUploader{dir}, defaultPath, toEncrypt)
208+
return c.TarUpload(manifest, &DirectoryUploader{dir}, defaultPath, toEncrypt, toPin)
204209
}
205210

206211
// DownloadDirectory downloads the files contained in a swarm manifest under
@@ -358,12 +363,13 @@ func (c *Client) DownloadFile(hash, path, dest, credentials string) error {
358363
}
359364

360365
// UploadManifest uploads the given manifest to swarm
361-
func (c *Client) UploadManifest(m *api.Manifest, toEncrypt bool) (string, error) {
366+
func (c *Client) UploadManifest(m *api.Manifest, toEncrypt bool, toPin bool) (string, error) {
362367
data, err := json.Marshal(m)
363368
if err != nil {
364369
return "", err
365370
}
366-
return c.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt)
371+
372+
return c.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt, toPin)
367373
}
368374

369375
// DownloadManifest downloads a swarm manifest
@@ -498,7 +504,7 @@ type UploadFn func(file *File) error
498504

499505
// TarUpload uses the given Uploader to upload files to swarm as a tar stream,
500506
// returning the resulting manifest hash
501-
func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, toEncrypt bool) (string, error) {
507+
func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, toEncrypt bool, toPin bool) (string, error) {
502508
ctx, sp := spancontext.StartSpan(context.Background(), "api.client.tarupload")
503509
defer sp.Finish()
504510

@@ -540,6 +546,11 @@ func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, t
540546

541547
req.Header.Set(swarmhttp.SwarmTagHeaderName, tag)
542548

549+
// Set the pinning header if the file is to be pinned
550+
if toPin {
551+
req.Header.Set(swarmhttp.PinHeaderName, "true")
552+
}
553+
543554
// use 'Expect: 100-continue' so we don't send the request body if
544555
// the server refuses the request
545556
req.Header.Set("Expect", "100-continue")
@@ -591,7 +602,7 @@ func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, t
591602

592603
// MultipartUpload uses the given Uploader to upload files to swarm as a
593604
// multipart form, returning the resulting manifest hash
594-
func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error) {
605+
func (c *Client) MultipartUpload(hash string, uploader Uploader, toPin bool) (string, error) {
595606
reqR, reqW := io.Pipe()
596607
defer reqR.Close()
597608
req, err := http.NewRequest("POST", c.Gateway+"/bzz:/"+hash, reqR)
@@ -606,6 +617,9 @@ func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error)
606617
mw := multipart.NewWriter(reqW)
607618
req.Header.Set("Content-Type", fmt.Sprintf("multipart/form-data; boundary=%q", mw.Boundary()))
608619
req.Header.Set(swarmhttp.SwarmTagHeaderName, fmt.Sprintf("multipart_upload_%d", time.Now().Unix()))
620+
if toPin {
621+
req.Header.Set(swarmhttp.PinHeaderName, "true")
622+
}
609623

610624
// define an UploadFn which adds files to the multipart form
611625
uploadFn := func(file *File) error {

api/client/client_test.go

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,39 +36,47 @@ import (
3636
)
3737

3838
func serverFunc(api *api.API) swarmhttp.TestServer {
39-
return swarmhttp.NewServer(api, "")
39+
return swarmhttp.NewServer(api, nil, "")
4040
}
4141

4242
// TestClientUploadDownloadRaw test uploading and downloading raw data to swarm
4343
func TestClientUploadDownloadRaw(t *testing.T) {
44-
testClientUploadDownloadRaw(false, t)
44+
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil, nil)
45+
defer srv.Close()
46+
47+
data := []byte("foo123")
48+
testClientUploadDownloadRaw(srv, false, t, data, false)
49+
50+
// check the tag was created successfully
51+
tag := srv.Tags.All()[0]
52+
testutil.CheckTag(t, tag, 1, 1, 0, 1)
4553
}
4654

4755
func TestClientUploadDownloadRawEncrypted(t *testing.T) {
56+
4857
if testutil.RaceEnabled {
4958
t.Skip("flaky with -race on Travis")
5059
// See: https://github.com/ethersphere/go-ethereum/issues/1254
5160
}
5261

53-
testClientUploadDownloadRaw(true, t)
54-
}
55-
56-
func testClientUploadDownloadRaw(toEncrypt bool, t *testing.T) {
57-
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
62+
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil, nil)
5863
defer srv.Close()
5964

60-
client := NewClient(srv.URL)
61-
62-
// upload some raw data
6365
data := []byte("foo123")
64-
hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt)
65-
if err != nil {
66-
t.Fatal(err)
67-
}
66+
testClientUploadDownloadRaw(srv, true, t, data, false)
6867

6968
// check the tag was created successfully
7069
tag := srv.Tags.All()[0]
7170
testutil.CheckTag(t, tag, 1, 1, 0, 1)
71+
}
72+
73+
func testClientUploadDownloadRaw(srv *swarmhttp.TestSwarmServer, toEncrypt bool, t *testing.T, data []byte, toPin bool) string {
74+
client := NewClient(srv.URL)
75+
76+
hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt, toPin)
77+
if err != nil {
78+
t.Fatal(err)
79+
}
7280

7381
// check we can download the same data
7482
res, isEncrypted, err := client.DownloadRaw(hash)
@@ -86,6 +94,8 @@ func testClientUploadDownloadRaw(toEncrypt bool, t *testing.T) {
8694
if !bytes.Equal(gotData, data) {
8795
t.Fatalf("expected downloaded data to be %q, got %q", data, gotData)
8896
}
97+
98+
return hash
8999
}
90100

91101
// TestClientUploadDownloadFiles test uploading and downloading files to swarm
@@ -98,12 +108,13 @@ func TestClientUploadDownloadFilesEncrypted(t *testing.T) {
98108
testClientUploadDownloadFiles(true, t)
99109
}
100110

101-
func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) {
102-
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
111+
func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) string {
112+
113+
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil, nil)
103114
defer srv.Close()
104115

105116
client := NewClient(srv.URL)
106-
upload := func(manifest, path string, data []byte) string {
117+
upload := func(manifest, path string, data []byte, toPin bool) string {
107118
file := &File{
108119
ReadCloser: ioutil.NopCloser(bytes.NewReader(data)),
109120
ManifestEntry: api.ManifestEntry{
@@ -112,7 +123,7 @@ func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) {
112123
Size: int64(len(data)),
113124
},
114125
}
115-
hash, err := client.Upload(file, manifest, toEncrypt)
126+
hash, err := client.Upload(file, manifest, toEncrypt, toPin)
116127
if err != nil {
117128
t.Fatal(err)
118129
}
@@ -141,25 +152,27 @@ func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) {
141152

142153
// upload a file to the root of a manifest
143154
rootData := []byte("some-data")
144-
rootHash := upload("", "", rootData)
155+
rootHash := upload("", "", rootData, false)
145156

146157
// check we can download the root file
147158
checkDownload(rootHash, "", rootData)
148159

149160
// upload another file to the same manifest
150161
otherData := []byte("some-other-data")
151-
newHash := upload(rootHash, "some/other/path", otherData)
162+
newHash := upload(rootHash, "some/other/path", otherData, false)
152163

153164
// check we can download both files from the new manifest
154165
checkDownload(newHash, "", rootData)
155166
checkDownload(newHash, "some/other/path", otherData)
156167

157168
// replace the root file with different data
158-
newHash = upload(newHash, "", otherData)
169+
newHash = upload(newHash, "", otherData, false)
159170

160171
// check both files have the other data
161172
checkDownload(newHash, "", otherData)
162173
checkDownload(newHash, "some/other/path", otherData)
174+
175+
return newHash
163176
}
164177

165178
var testDirFiles = []string{
@@ -194,10 +207,10 @@ func newTestDirectory(t *testing.T) string {
194207
return dir
195208
}
196209

197-
// TestClientUploadDownloadDirectory tests uploading and downloading a
210+
// TestClientUploadDownloadDirectory tests uploading and downloading
198211
// directory of files to a swarm manifest
199212
func TestClientUploadDownloadDirectory(t *testing.T) {
200-
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
213+
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil, nil)
201214
defer srv.Close()
202215

203216
dir := newTestDirectory(t)
@@ -206,7 +219,7 @@ func TestClientUploadDownloadDirectory(t *testing.T) {
206219
// upload the directory
207220
client := NewClient(srv.URL)
208221
defaultPath := testDirFiles[0]
209-
hash, err := client.UploadDirectory(dir, defaultPath, "", false)
222+
hash, err := client.UploadDirectory(dir, defaultPath, "", false, false)
210223
if err != nil {
211224
t.Fatalf("error uploading directory: %s", err)
212225
}
@@ -267,14 +280,14 @@ func TestClientFileListEncrypted(t *testing.T) {
267280
}
268281

269282
func testClientFileList(toEncrypt bool, t *testing.T) {
270-
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
283+
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil, nil)
271284
defer srv.Close()
272285

273286
dir := newTestDirectory(t)
274287
defer os.RemoveAll(dir)
275288

276289
client := NewClient(srv.URL)
277-
hash, err := client.UploadDirectory(dir, "", "", toEncrypt)
290+
hash, err := client.UploadDirectory(dir, "", "", toEncrypt, false)
278291
if err != nil {
279292
t.Fatalf("error uploading directory: %s", err)
280293
}
@@ -325,14 +338,14 @@ func testClientFileList(toEncrypt bool, t *testing.T) {
325338
// TestClientMultipartUpload tests uploading files to swarm using a multipart
326339
// upload
327340
func TestClientMultipartUpload(t *testing.T) {
328-
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
341+
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil, nil)
329342
defer srv.Close()
330343

331344
// define an uploader which uploads testDirFiles with some data
332345
// note: this test should result in SEEN chunks. assert accordingly
333-
data := []byte("some-data")
334346
uploader := UploaderFunc(func(upload UploadFn) error {
335347
for _, name := range testDirFiles {
348+
data := []byte(name)
336349
file := &File{
337350
ReadCloser: ioutil.NopCloser(bytes.NewReader(data)),
338351
ManifestEntry: api.ManifestEntry{
@@ -350,14 +363,14 @@ func TestClientMultipartUpload(t *testing.T) {
350363

351364
// upload the files as a multipart upload
352365
client := NewClient(srv.URL)
353-
hash, err := client.MultipartUpload("", uploader)
366+
hash, err := client.MultipartUpload("", uploader, false)
354367
if err != nil {
355368
t.Fatal(err)
356369
}
357370

358371
// check the tag was created successfully
359372
tag := srv.Tags.All()[0]
360-
testutil.CheckTag(t, tag, 9, 9, 7, 9)
373+
testutil.CheckTag(t, tag, 9, 9, 0, 9)
361374

362375
// check we can download the individual files
363376
checkDownloadFile := func(path string) {
@@ -370,8 +383,9 @@ func TestClientMultipartUpload(t *testing.T) {
370383
if err != nil {
371384
t.Fatal(err)
372385
}
373-
if !bytes.Equal(gotData, data) {
374-
t.Fatalf("expected data to be %q, got %q", data, gotData)
386+
// The content is the file name just to make them different
387+
if !bytes.Equal(gotData, []byte(path)) {
388+
t.Fatalf("expected data to be %q, got %q", path, gotData)
375389
}
376390
}
377391
for _, file := range testDirFiles {
@@ -398,7 +412,7 @@ func TestClientBzzWithFeed(t *testing.T) {
398412
signer, _ := newTestSigner()
399413

400414
// Initialize a Swarm test server
401-
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
415+
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil, nil)
402416
swarmClient := NewClient(srv.URL)
403417
defer srv.Close()
404418

@@ -433,7 +447,7 @@ func TestClientBzzWithFeed(t *testing.T) {
433447
}
434448

435449
// upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded.
436-
manifestAddressHex, err := swarmClient.Upload(f, "", false)
450+
manifestAddressHex, err := swarmClient.Upload(f, "", false, false)
437451
if err != nil {
438452
t.Fatalf("Error creating manifest: %s", err)
439453
}
@@ -516,7 +530,7 @@ func TestClientCreateUpdateFeed(t *testing.T) {
516530

517531
signer, _ := newTestSigner()
518532

519-
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
533+
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil, nil)
520534
client := NewClient(srv.URL)
521535
defer srv.Close()
522536

0 commit comments

Comments
 (0)