Remove multihash from Swarm bzz:// for Feeds (#18175)
This commit is contained in:
parent
0699287440
commit
2714e8f091
@ -16,7 +16,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/swarm/multihash"
|
||||
"github.com/ethereum/go-ethereum/swarm/storage/feed"
|
||||
colorable "github.com/mattn/go-colorable"
|
||||
"github.com/pborman/uuid"
|
||||
@ -36,7 +35,7 @@ func cliFeedUploadAndSync(c *cli.Context) error {
|
||||
|
||||
generateEndpoints(scheme, cluster, from, to)
|
||||
|
||||
log.Info("generating and uploading MRUs to " + endpoints[0] + " and syncing")
|
||||
log.Info("generating and uploading feeds to " + endpoints[0] + " and syncing")
|
||||
|
||||
// create a random private key to sign updates with and derive the address
|
||||
pkFile, err := ioutil.TempFile("", "swarm-feed-smoke-test")
|
||||
@ -218,8 +217,7 @@ func cliFeedUploadAndSync(c *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
multihashHex := hexutil.Encode(multihash.ToMultihash(hashBytes))
|
||||
|
||||
multihashHex := hexutil.Encode(hashBytes)
|
||||
fileHash, err := digest(f)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -7,7 +7,6 @@ swarm
|
||||
├── fuse ────────────────── @jmozah, @holisticode
|
||||
├── grafana_dashboards ──── @nonsense
|
||||
├── metrics ─────────────── @nonsense, @holisticode
|
||||
├── multihash ───────────── @nolash
|
||||
├── network ─────────────── ethersphere
|
||||
│ ├── bitvector ───────── @zelig, @janos, @gbalint
|
||||
│ ├── priorityqueue ───── @zelig, @janos, @gbalint
|
||||
|
@ -42,7 +42,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/swarm/log"
|
||||
"github.com/ethereum/go-ethereum/swarm/multihash"
|
||||
"github.com/ethereum/go-ethereum/swarm/spancontext"
|
||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||
"github.com/ethereum/go-ethereum/swarm/storage/feed"
|
||||
@ -417,7 +416,7 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage
|
||||
return reader, mimeType, status, nil, err
|
||||
}
|
||||
// get the data of the update
|
||||
_, rsrcData, err := a.feed.GetContent(entry.Feed)
|
||||
_, contentAddr, err := a.feed.GetContent(entry.Feed)
|
||||
if err != nil {
|
||||
apiGetNotFound.Inc(1)
|
||||
status = http.StatusNotFound
|
||||
@ -425,23 +424,23 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage
|
||||
return reader, mimeType, status, nil, err
|
||||
}
|
||||
|
||||
// extract multihash
|
||||
decodedMultihash, err := multihash.FromMultihash(rsrcData)
|
||||
if err != nil {
|
||||
// extract content hash
|
||||
if len(contentAddr) != storage.AddressLength {
|
||||
apiGetInvalid.Inc(1)
|
||||
status = http.StatusUnprocessableEntity
|
||||
log.Warn("invalid multihash in feed update", "err", err)
|
||||
return reader, mimeType, status, nil, err
|
||||
errorMessage := fmt.Sprintf("invalid swarm hash in feed update. Expected %d bytes. Got %d", storage.AddressLength, len(contentAddr))
|
||||
log.Warn(errorMessage)
|
||||
return reader, mimeType, status, nil, errors.New(errorMessage)
|
||||
}
|
||||
manifestAddr = storage.Address(decodedMultihash)
|
||||
log.Trace("feed update contains multihash", "key", manifestAddr)
|
||||
manifestAddr = storage.Address(contentAddr)
|
||||
log.Trace("feed update contains swarm hash", "key", manifestAddr)
|
||||
|
||||
// get the manifest the multihash digest points to
|
||||
// get the manifest the swarm hash points to
|
||||
trie, err := loadManifest(ctx, a.fileStore, manifestAddr, nil, NOOPDecrypt)
|
||||
if err != nil {
|
||||
apiGetNotFound.Inc(1)
|
||||
status = http.StatusNotFound
|
||||
log.Warn(fmt.Sprintf("loadManifestTrie (feed update multihash) error: %v", err))
|
||||
log.Warn(fmt.Sprintf("loadManifestTrie (feed update) error: %v", err))
|
||||
return reader, mimeType, status, nil, err
|
||||
}
|
||||
|
||||
@ -451,8 +450,8 @@ func (a *API) Get(ctx context.Context, decrypt DecryptFunc, manifestAddr storage
|
||||
if entry == nil {
|
||||
status = http.StatusNotFound
|
||||
apiGetNotFound.Inc(1)
|
||||
err = fmt.Errorf("manifest (feed update multihash) entry for '%s' not found", path)
|
||||
log.Trace("manifest (feed update multihash) entry not found", "key", manifestAddr, "path", path)
|
||||
err = fmt.Errorf("manifest (feed update) entry for '%s' not found", path)
|
||||
log.Trace("manifest (feed update) entry not found", "key", manifestAddr, "path", path)
|
||||
return reader, mimeType, status, nil, err
|
||||
}
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||
"github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/swarm/api"
|
||||
swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http"
|
||||
"github.com/ethereum/go-ethereum/swarm/multihash"
|
||||
"github.com/ethereum/go-ethereum/swarm/storage/feed"
|
||||
)
|
||||
|
||||
@ -368,58 +368,99 @@ func newTestSigner() (*feed.GenericSigner, error) {
|
||||
return feed.NewGenericSigner(privKey), nil
|
||||
}
|
||||
|
||||
// test the transparent resolving of multihash feed updates with bzz:// scheme
|
||||
// Test the transparent resolving of feed updates with bzz:// scheme
|
||||
//
|
||||
// first upload data, and store the multihash to the resulting manifest in a feed update
|
||||
// retrieving the update with the multihash should return the manifest pointing directly to the data
|
||||
// First upload data to bzz:, and store the Swarm hash to the resulting manifest in a feed update.
|
||||
// This effectively uses a feed to store a pointer to content rather than the content itself
|
||||
// Retrieving the update with the Swarm hash should return the manifest pointing directly to the data
|
||||
// and raw retrieve of that hash should return the data
|
||||
func TestClientCreateFeedMultihash(t *testing.T) {
|
||||
func TestClientBzzWithFeed(t *testing.T) {
|
||||
|
||||
signer, _ := newTestSigner()
|
||||
|
||||
// Initialize a Swarm test server
|
||||
srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil)
|
||||
client := NewClient(srv.URL)
|
||||
swarmClient := NewClient(srv.URL)
|
||||
defer srv.Close()
|
||||
|
||||
// add the data our multihash aliased manifest will point to
|
||||
databytes := []byte("bar")
|
||||
// put together some data for our test:
|
||||
dataBytes := []byte(`
|
||||
//
|
||||
// Create some data our manifest will point to. Data that could be very big and wouldn't fit in a feed update.
|
||||
// So what we are going to do is upload it to Swarm bzz:// and obtain a **manifest hash** pointing to it:
|
||||
//
|
||||
// MANIFEST HASH --> DATA
|
||||
//
|
||||
// Then, we store that **manifest hash** into a Swarm Feed update. Once we have done this,
|
||||
// we can use the **feed manifest hash** in bzz:// instead, this way: bzz://feed-manifest-hash.
|
||||
//
|
||||
// FEED MANIFEST HASH --> MANIFEST HASH --> DATA
|
||||
//
|
||||
// Given that we can update the feed at any time with a new **manifest hash** but the **feed manifest hash**
|
||||
// stays constant, we have effectively created a fixed address to changing content. (Applause)
|
||||
//
|
||||
// FEED MANIFEST HASH (the same) --> MANIFEST HASH(2) --> DATA(2)
|
||||
//
|
||||
`)
|
||||
|
||||
swarmHash, err := client.UploadRaw(bytes.NewReader(databytes), int64(len(databytes)), false)
|
||||
if err != nil {
|
||||
t.Fatalf("Error uploading raw test data: %s", err)
|
||||
// Create a virtual File out of memory containing the above data
|
||||
f := &File{
|
||||
ReadCloser: ioutil.NopCloser(bytes.NewReader(dataBytes)),
|
||||
ManifestEntry: api.ManifestEntry{
|
||||
ContentType: "text/plain",
|
||||
Mode: 0660,
|
||||
Size: int64(len(dataBytes)),
|
||||
},
|
||||
}
|
||||
|
||||
s := common.FromHex(swarmHash)
|
||||
mh := multihash.ToMultihash(s)
|
||||
// upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded.
|
||||
manifestAddressHex, err := swarmClient.Upload(f, "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating manifest: %s", err)
|
||||
}
|
||||
|
||||
// our feed topic
|
||||
topic, _ := feed.NewTopic("foo.eth", nil)
|
||||
// convert the hex-encoded manifest hash to a 32-byte slice
|
||||
manifestAddress := common.FromHex(manifestAddressHex)
|
||||
|
||||
createRequest := feed.NewFirstRequest(topic)
|
||||
if len(manifestAddress) != storage.AddressLength {
|
||||
t.Fatalf("Something went wrong. Got a hash of an unexpected length. Expected %d bytes. Got %d", storage.AddressLength, len(manifestAddress))
|
||||
}
|
||||
|
||||
createRequest.SetData(mh)
|
||||
if err := createRequest.Sign(signer); err != nil {
|
||||
// Now create a **feed manifest**. For that, we need a topic:
|
||||
topic, _ := feed.NewTopic("interesting topic indeed", nil)
|
||||
|
||||
// Build a feed request to update data
|
||||
request := feed.NewFirstRequest(topic)
|
||||
|
||||
// Put the 32-byte address of the manifest into the feed update
|
||||
request.SetData(manifestAddress)
|
||||
|
||||
// Sign the update
|
||||
if err := request.Sign(signer); err != nil {
|
||||
t.Fatalf("Error signing update: %s", err)
|
||||
}
|
||||
|
||||
feedManifestHash, err := client.CreateFeedWithManifest(createRequest)
|
||||
|
||||
// Publish the update and at the same time request a **feed manifest** to be created
|
||||
feedManifestAddressHex, err := swarmClient.CreateFeedWithManifest(request)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating feed manifest: %s", err)
|
||||
}
|
||||
|
||||
correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b"
|
||||
if feedManifestHash != correctManifestAddrHex {
|
||||
t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash)
|
||||
// Check we have received the exact **feed manifest** to be expected
|
||||
// given the topic and user signing the updates:
|
||||
correctFeedManifestAddrHex := "747c402e5b9dc715a25a4393147512167bab018a007fad7cdcd9adc7fce1ced2"
|
||||
if feedManifestAddressHex != correctFeedManifestAddrHex {
|
||||
t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctFeedManifestAddrHex, feedManifestAddressHex)
|
||||
}
|
||||
|
||||
// Check we get a not found error when trying to get feed updates with a made-up manifest
|
||||
_, err = client.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
|
||||
_, err = swarmClient.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
|
||||
if err != ErrNoFeedUpdatesFound {
|
||||
t.Fatalf("Expected to receive ErrNoFeedUpdatesFound error. Got: %s", err)
|
||||
}
|
||||
|
||||
reader, err := client.QueryFeed(nil, correctManifestAddrHex)
|
||||
// If we query the feed directly we should get **manifest hash** back:
|
||||
reader, err := swarmClient.QueryFeed(nil, correctFeedManifestAddrHex)
|
||||
if err != nil {
|
||||
t.Fatalf("Error retrieving feed updates: %s", err)
|
||||
}
|
||||
@ -428,10 +469,27 @@ func TestClientCreateFeedMultihash(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(mh, gotData) {
|
||||
t.Fatalf("Expected: %v, got %v", mh, gotData)
|
||||
|
||||
//Check that indeed the **manifest hash** is retrieved
|
||||
if !bytes.Equal(manifestAddress, gotData) {
|
||||
t.Fatalf("Expected: %v, got %v", manifestAddress, gotData)
|
||||
}
|
||||
|
||||
// Now the final test we were looking for: Use bzz://<feed-manifest> and that should resolve all manifests
|
||||
// and return the original data directly:
|
||||
f, err = swarmClient.Download(feedManifestAddressHex, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gotData, err = ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check that we get back the original data:
|
||||
if !bytes.Equal(dataBytes, gotData) {
|
||||
t.Fatalf("Expected: %v, got %v", manifestAddress, gotData)
|
||||
}
|
||||
}
|
||||
|
||||
// TestClientCreateUpdateFeed will check that feeds can be created and updated via the HTTP client.
|
||||
|
@ -45,7 +45,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/swarm/api"
|
||||
swarm "github.com/ethereum/go-ethereum/swarm/api/client"
|
||||
"github.com/ethereum/go-ethereum/swarm/multihash"
|
||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||
"github.com/ethereum/go-ethereum/swarm/storage/feed"
|
||||
"github.com/ethereum/go-ethereum/swarm/testutil"
|
||||
@ -69,60 +68,91 @@ func newTestSigner() (*feed.GenericSigner, error) {
|
||||
return feed.NewGenericSigner(privKey), nil
|
||||
}
|
||||
|
||||
// test the transparent resolving of multihash-containing feed updates with bzz:// scheme
|
||||
// Test the transparent resolving of feed updates with bzz:// scheme
|
||||
//
|
||||
// first upload data, and store the multihash to the resulting manifest in a feed update
|
||||
// retrieving the update with the multihash should return the manifest pointing directly to the data
|
||||
// First upload data to bzz:, and store the Swarm hash to the resulting manifest in a feed update.
|
||||
// This effectively uses a feed to store a pointer to content rather than the content itself
|
||||
// Retrieving the update with the Swarm hash should return the manifest pointing directly to the data
|
||||
// and raw retrieve of that hash should return the data
|
||||
func TestBzzFeedMultihash(t *testing.T) {
|
||||
func TestBzzWithFeed(t *testing.T) {
|
||||
|
||||
signer, _ := newTestSigner()
|
||||
|
||||
// Initialize Swarm test server
|
||||
srv := NewTestSwarmServer(t, serverFunc, nil)
|
||||
defer srv.Close()
|
||||
|
||||
// add the data our multihash aliased manifest will point to
|
||||
databytes := "bar"
|
||||
testBzzUrl := fmt.Sprintf("%s/bzz:/", srv.URL)
|
||||
resp, err := http.Post(testBzzUrl, "text/plain", bytes.NewReader([]byte(databytes)))
|
||||
// put together some data for our test:
|
||||
dataBytes := []byte(`
|
||||
//
|
||||
// Create some data our manifest will point to. Data that could be very big and wouldn't fit in a feed update.
|
||||
// So what we are going to do is upload it to Swarm bzz:// and obtain a **manifest hash** pointing to it:
|
||||
//
|
||||
// MANIFEST HASH --> DATA
|
||||
//
|
||||
// Then, we store that **manifest hash** into a Swarm Feed update. Once we have done this,
|
||||
// we can use the **feed manifest hash** in bzz:// instead, this way: bzz://feed-manifest-hash.
|
||||
//
|
||||
// FEED MANIFEST HASH --> MANIFEST HASH --> DATA
|
||||
//
|
||||
// Given that we can update the feed at any time with a new **manifest hash** but the **feed manifest hash**
|
||||
// stays constant, we have effectively created a fixed address to changing content. (Applause)
|
||||
//
|
||||
// FEED MANIFEST HASH (the same) --> MANIFEST HASH(2) --> DATA(2) ...
|
||||
//
|
||||
`)
|
||||
|
||||
// POST data to bzz and get back a content-addressed **manifest hash** pointing to it.
|
||||
resp, err := http.Post(fmt.Sprintf("%s/bzz:/", srv.URL), "text/plain", bytes.NewReader([]byte(dataBytes)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("err %s", resp.Status)
|
||||
}
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
manifestAddressHex, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := common.FromHex(string(b))
|
||||
mh := multihash.ToMultihash(s)
|
||||
|
||||
log.Info("added data", "manifest", string(b), "data", common.ToHex(mh))
|
||||
manifestAddress := common.FromHex(string(manifestAddressHex))
|
||||
|
||||
topic, _ := feed.NewTopic("foo.eth", nil)
|
||||
log.Info("added data", "manifest", string(manifestAddressHex))
|
||||
|
||||
// At this point we have uploaded the data and have a manifest pointing to it
|
||||
// Now store that manifest address in a feed update.
|
||||
// We also want a feed manifest, so we can use it to refer to the feed.
|
||||
|
||||
// First, create a topic for our feed:
|
||||
topic, _ := feed.NewTopic("interesting topic indeed", nil)
|
||||
|
||||
// Create a feed update request:
|
||||
updateRequest := feed.NewFirstRequest(topic)
|
||||
|
||||
updateRequest.SetData(mh)
|
||||
// Store the **manifest address** as data into the feed update.
|
||||
updateRequest.SetData(manifestAddress)
|
||||
|
||||
// Sign the update
|
||||
if err := updateRequest.Sign(signer); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
log.Info("added data", "manifest", string(b), "data", common.ToHex(mh))
|
||||
log.Info("added data", "data", common.ToHex(manifestAddress))
|
||||
|
||||
testUrl, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL))
|
||||
// Build the feed update http request:
|
||||
feedUpdateURL, err := url.Parse(fmt.Sprintf("%s/bzz-feed:/", srv.URL))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
query := testUrl.Query()
|
||||
query := feedUpdateURL.Query()
|
||||
body := updateRequest.AppendValues(query) // this adds all query parameters and returns the data to be posted
|
||||
query.Set("manifest", "1") // indicate we want a manifest back
|
||||
testUrl.RawQuery = query.Encode()
|
||||
query.Set("manifest", "1") // indicate we want a feed manifest back
|
||||
feedUpdateURL.RawQuery = query.Encode()
|
||||
|
||||
// create the multihash update
|
||||
resp, err = http.Post(testUrl.String(), "application/octet-stream", bytes.NewReader(body))
|
||||
// submit the feed update request to Swarm
|
||||
resp, err = http.Post(feedUpdateURL.String(), "application/octet-stream", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -130,24 +160,25 @@ func TestBzzFeedMultihash(t *testing.T) {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("err %s", resp.Status)
|
||||
}
|
||||
b, err = ioutil.ReadAll(resp.Body)
|
||||
|
||||
feedManifestAddressHex, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rsrcResp := &storage.Address{}
|
||||
err = json.Unmarshal(b, rsrcResp)
|
||||
feedManifestAddress := &storage.Address{}
|
||||
err = json.Unmarshal(feedManifestAddressHex, feedManifestAddress)
|
||||
if err != nil {
|
||||
t.Fatalf("data %s could not be unmarshaled: %v", b, err)
|
||||
t.Fatalf("data %s could not be unmarshaled: %v", feedManifestAddressHex, err)
|
||||
}
|
||||
|
||||
correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b"
|
||||
if rsrcResp.Hex() != correctManifestAddrHex {
|
||||
t.Fatalf("Response feed manifest address mismatch, expected '%s', got '%s'", correctManifestAddrHex, rsrcResp.Hex())
|
||||
correctManifestAddrHex := "747c402e5b9dc715a25a4393147512167bab018a007fad7cdcd9adc7fce1ced2"
|
||||
if feedManifestAddress.Hex() != correctManifestAddrHex {
|
||||
t.Fatalf("Response feed manifest address mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestAddress.Hex())
|
||||
}
|
||||
|
||||
// get bzz manifest transparent feed update resolve
|
||||
testBzzUrl = fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp)
|
||||
resp, err = http.Get(testBzzUrl)
|
||||
getBzzURL := fmt.Sprintf("%s/bzz:/%s", srv.URL, feedManifestAddress)
|
||||
resp, err = http.Get(getBzzURL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -155,12 +186,12 @@ func TestBzzFeedMultihash(t *testing.T) {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("err %s", resp.Status)
|
||||
}
|
||||
b, err = ioutil.ReadAll(resp.Body)
|
||||
retrievedData, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b, []byte(databytes)) {
|
||||
t.Fatalf("retrieved data mismatch, expected %x, got %x", databytes, b)
|
||||
if !bytes.Equal(retrievedData, []byte(dataBytes)) {
|
||||
t.Fatalf("retrieved data mismatch, expected %x, got %x", dataBytes, retrievedData)
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,7 +276,8 @@ func TestBzzFeed(t *testing.T) {
|
||||
t.Fatalf("Expected manifest Feed '%s', got '%s'", correctFeedHex, manifest.Entries[0].Feed.Hex())
|
||||
}
|
||||
|
||||
// get bzz manifest transparent feed update resolve
|
||||
// take the chance to have bzz: crash on resolving a feed update that does not contain
|
||||
// a swarm hash:
|
||||
testBzzUrl := fmt.Sprintf("%s/bzz:/%s", srv.URL, rsrcResp)
|
||||
resp, err = http.Get(testBzzUrl)
|
||||
if err != nil {
|
||||
@ -253,7 +285,7 @@ func TestBzzFeed(t *testing.T) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
t.Fatal("Expected error status since feed update does not contain multihash. Received 200 OK")
|
||||
t.Fatal("Expected error status since feed update does not contain a Swarm hash. Received 200 OK")
|
||||
}
|
||||
_, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
|
@ -1,92 +0,0 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMultihashLength = 32
|
||||
defaultMultihashTypeCode = 0x1b
|
||||
)
|
||||
|
||||
var (
|
||||
multihashTypeCode uint8
|
||||
MultihashLength = defaultMultihashLength
|
||||
)
|
||||
|
||||
func init() {
|
||||
multihashTypeCode = defaultMultihashTypeCode
|
||||
MultihashLength = defaultMultihashLength
|
||||
}
|
||||
|
||||
// check if valid swarm multihash
|
||||
func isSwarmMultihashType(code uint8) bool {
|
||||
return code == multihashTypeCode
|
||||
}
|
||||
|
||||
// GetMultihashLength returns the digest length of the provided multihash
|
||||
// It will fail if the multihash is not a valid swarm mulithash
|
||||
func GetMultihashLength(data []byte) (int, int, error) {
|
||||
cursor := 0
|
||||
typ, c := binary.Uvarint(data)
|
||||
if c <= 0 {
|
||||
return 0, 0, errors.New("unreadable hashtype field")
|
||||
}
|
||||
if !isSwarmMultihashType(uint8(typ)) {
|
||||
return 0, 0, fmt.Errorf("hash code %x is not a swarm hashtype", typ)
|
||||
}
|
||||
cursor += c
|
||||
hashlength, c := binary.Uvarint(data[cursor:])
|
||||
if c <= 0 {
|
||||
return 0, 0, errors.New("unreadable length field")
|
||||
}
|
||||
cursor += c
|
||||
|
||||
// we cheekily assume hashlength < maxint
|
||||
inthashlength := int(hashlength)
|
||||
if len(data[c:]) < inthashlength {
|
||||
return 0, 0, errors.New("length mismatch")
|
||||
}
|
||||
return inthashlength, cursor, nil
|
||||
}
|
||||
|
||||
// FromMulithash returns the digest portion of the multihash
|
||||
// It will fail if the multihash is not a valid swarm multihash
|
||||
func FromMultihash(data []byte) ([]byte, error) {
|
||||
hashLength, _, err := GetMultihashLength(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data[len(data)-hashLength:], nil
|
||||
}
|
||||
|
||||
// ToMulithash wraps the provided digest data with a swarm mulithash header
|
||||
func ToMultihash(hashData []byte) []byte {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
b := make([]byte, 8)
|
||||
c := binary.PutUvarint(b, uint64(multihashTypeCode))
|
||||
buf.Write(b[:c])
|
||||
c = binary.PutUvarint(b, uint64(len(hashData)))
|
||||
buf.Write(b[:c])
|
||||
buf.Write(hashData)
|
||||
return buf.Bytes()
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package multihash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// parse multihash, and check that invalid multihashes fail
|
||||
func TestCheckMultihash(t *testing.T) {
|
||||
hashbytes := make([]byte, 32)
|
||||
c, err := rand.Read(hashbytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if c < 32 {
|
||||
t.Fatal("short read")
|
||||
}
|
||||
|
||||
expected := ToMultihash(hashbytes)
|
||||
|
||||
l, hl, _ := GetMultihashLength(expected)
|
||||
if l != 32 {
|
||||
t.Fatalf("expected length %d, got %d", 32, l)
|
||||
} else if hl != 2 {
|
||||
t.Fatalf("expected header length %d, got %d", 2, hl)
|
||||
}
|
||||
if _, _, err := GetMultihashLength(expected[1:]); err == nil {
|
||||
t.Fatal("expected failure on corrupt header")
|
||||
}
|
||||
if _, _, err := GetMultihashLength(expected[:len(expected)-2]); err == nil {
|
||||
t.Fatal("expected failure on short content")
|
||||
}
|
||||
dh, _ := FromMultihash(expected)
|
||||
if !bytes.Equal(dh, hashbytes) {
|
||||
t.Fatalf("expected content hash %x, got %x", hashbytes, dh)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user