Unverified Commit e5677114 authored by Viktor Trón's avatar Viktor Trón Committed by GitHub

Merge pull request #17796 from epiclabs-io/mru-feeds

swarm/storage/feeds: Renamed MRU to Swarm Feeds
parents 303b9966 de01178c
...@@ -27,6 +27,6 @@ swarm/services @zelig ...@@ -27,6 +27,6 @@ swarm/services @zelig
swarm/state @justelad swarm/state @justelad
swarm/storage/encryption @gbalint @zelig @nagydani swarm/storage/encryption @gbalint @zelig @nagydani
swarm/storage/mock @janos swarm/storage/mock @janos
swarm/storage/mru @nolash swarm/storage/feed @nolash @jpeletier
swarm/testutil @lmars swarm/testutil @lmars
whisper/ @gballet @gluk256 whisper/ @gballet @gluk256
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// Command resource allows the user to create and update signed mutable resource updates // Command feed allows the user to create and update signed Swarm feeds
package main package main
import ( import (
...@@ -27,17 +27,17 @@ import ( ...@@ -27,17 +27,17 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
swarm "github.com/ethereum/go-ethereum/swarm/api/client" swarm "github.com/ethereum/go-ethereum/swarm/api/client"
"github.com/ethereum/go-ethereum/swarm/storage/mru" "github.com/ethereum/go-ethereum/swarm/storage/feed"
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )
func NewGenericSigner(ctx *cli.Context) mru.Signer { func NewGenericSigner(ctx *cli.Context) feed.Signer {
return mru.NewGenericSigner(getPrivKey(ctx)) return feed.NewGenericSigner(getPrivKey(ctx))
} }
func getTopic(ctx *cli.Context) (topic mru.Topic) { func getTopic(ctx *cli.Context) (topic feed.Topic) {
var name = ctx.String(SwarmResourceNameFlag.Name) var name = ctx.String(SwarmFeedNameFlag.Name)
var relatedTopic = ctx.String(SwarmResourceTopicFlag.Name) var relatedTopic = ctx.String(SwarmFeedTopicFlag.Name)
var relatedTopicBytes []byte var relatedTopicBytes []byte
var err error var err error
...@@ -48,42 +48,42 @@ func getTopic(ctx *cli.Context) (topic mru.Topic) { ...@@ -48,42 +48,42 @@ func getTopic(ctx *cli.Context) (topic mru.Topic) {
} }
} }
topic, err = mru.NewTopic(name, relatedTopicBytes) topic, err = feed.NewTopic(name, relatedTopicBytes)
if err != nil { if err != nil {
utils.Fatalf("Error parsing topic: %s", err) utils.Fatalf("Error parsing topic: %s", err)
} }
return topic return topic
} }
// swarm resource create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]] // swarm feed create <frequency> [--name <name>] [--data <0x Hexdata> [--multihash=false]]
// swarm resource update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false] // swarm feed update <Manifest Address or ENS domain> <0x Hexdata> [--multihash=false]
// swarm resource info <Manifest Address or ENS domain> // swarm feed info <Manifest Address or ENS domain>
func resourceCreate(ctx *cli.Context) { func feedCreateManifest(ctx *cli.Context) {
var ( var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi) client = swarm.NewClient(bzzapi)
) )
newResourceRequest := mru.NewFirstRequest(getTopic(ctx)) newFeedUpdateRequest := feed.NewFirstRequest(getTopic(ctx))
newResourceRequest.View.User = resourceGetUser(ctx) newFeedUpdateRequest.Feed.User = feedGetUser(ctx)
manifestAddress, err := client.CreateResource(newResourceRequest) manifestAddress, err := client.CreateFeedWithManifest(newFeedUpdateRequest)
if err != nil { if err != nil {
utils.Fatalf("Error creating resource: %s", err.Error()) utils.Fatalf("Error creating feed manifest: %s", err.Error())
return return
} }
fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up) fmt.Println(manifestAddress) // output manifest address to the user in a single line (useful for other commands to pick up)
} }
func resourceUpdate(ctx *cli.Context) { func feedUpdate(ctx *cli.Context) {
args := ctx.Args() args := ctx.Args()
var ( var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi) client = swarm.NewClient(bzzapi)
manifestAddressOrDomain = ctx.String(SwarmResourceManifestFlag.Name) manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name)
) )
if len(args) < 1 { if len(args) < 1 {
...@@ -100,20 +100,20 @@ func resourceUpdate(ctx *cli.Context) { ...@@ -100,20 +100,20 @@ func resourceUpdate(ctx *cli.Context) {
return return
} }
var updateRequest *mru.Request var updateRequest *feed.Request
var query *mru.Query var query *feed.Query
if manifestAddressOrDomain == "" { if manifestAddressOrDomain == "" {
query = new(mru.Query) query = new(feed.Query)
query.User = signer.Address() query.User = signer.Address()
query.Topic = getTopic(ctx) query.Topic = getTopic(ctx)
} }
// Retrieve resource status and metadata out of the manifest // Retrieve a feed update request
updateRequest, err = client.GetResourceMetadata(query, manifestAddressOrDomain) updateRequest, err = client.GetFeedRequest(query, manifestAddressOrDomain)
if err != nil { if err != nil {
utils.Fatalf("Error retrieving resource status: %s", err.Error()) utils.Fatalf("Error retrieving feed status: %s", err.Error())
} }
// set the new data // set the new data
...@@ -121,34 +121,34 @@ func resourceUpdate(ctx *cli.Context) { ...@@ -121,34 +121,34 @@ func resourceUpdate(ctx *cli.Context) {
// sign update // sign update
if err = updateRequest.Sign(signer); err != nil { if err = updateRequest.Sign(signer); err != nil {
utils.Fatalf("Error signing resource update: %s", err.Error()) utils.Fatalf("Error signing feed update: %s", err.Error())
} }
// post update // post update
err = client.UpdateResource(updateRequest) err = client.UpdateFeed(updateRequest)
if err != nil { if err != nil {
utils.Fatalf("Error updating resource: %s", err.Error()) utils.Fatalf("Error updating feed: %s", err.Error())
return return
} }
} }
func resourceInfo(ctx *cli.Context) { func feedInfo(ctx *cli.Context) {
var ( var (
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/") bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
client = swarm.NewClient(bzzapi) client = swarm.NewClient(bzzapi)
manifestAddressOrDomain = ctx.String(SwarmResourceManifestFlag.Name) manifestAddressOrDomain = ctx.String(SwarmFeedManifestFlag.Name)
) )
var query *mru.Query var query *feed.Query
if manifestAddressOrDomain == "" { if manifestAddressOrDomain == "" {
query = new(mru.Query) query = new(feed.Query)
query.Topic = getTopic(ctx) query.Topic = getTopic(ctx)
query.User = resourceGetUser(ctx) query.User = feedGetUser(ctx)
} }
metadata, err := client.GetResourceMetadata(query, manifestAddressOrDomain) metadata, err := client.GetFeedRequest(query, manifestAddressOrDomain)
if err != nil { if err != nil {
utils.Fatalf("Error retrieving resource metadata: %s", err.Error()) utils.Fatalf("Error retrieving feed metadata: %s", err.Error())
return return
} }
encodedMetadata, err := metadata.MarshalJSON() encodedMetadata, err := metadata.MarshalJSON()
...@@ -158,8 +158,8 @@ func resourceInfo(ctx *cli.Context) { ...@@ -158,8 +158,8 @@ func resourceInfo(ctx *cli.Context) {
fmt.Println(string(encodedMetadata)) fmt.Println(string(encodedMetadata))
} }
func resourceGetUser(ctx *cli.Context) common.Address { func feedGetUser(ctx *cli.Context) common.Address {
var user = ctx.String(SwarmResourceUserFlag.Name) var user = ctx.String(SwarmFeedUserFlag.Name)
if user != "" { if user != "" {
return common.HexToAddress(user) return common.HexToAddress(user)
} }
......
...@@ -26,11 +26,11 @@ import ( ...@@ -26,11 +26,11 @@ import (
"testing" "testing"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
"github.com/ethereum/go-ethereum/swarm/testutil" "github.com/ethereum/go-ethereum/swarm/testutil"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/swarm/storage/mru" "github.com/ethereum/go-ethereum/swarm/storage/feed"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -38,12 +38,12 @@ import ( ...@@ -38,12 +38,12 @@ import (
swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http"
) )
func TestCLIResourceUpdate(t *testing.T) { func TestCLIFeedUpdate(t *testing.T) {
srv := testutil.NewTestSwarmServer(t, func(api *api.API) testutil.TestServer { srv := testutil.NewTestSwarmServer(t, func(api *api.API) testutil.TestServer {
return swarmhttp.NewServer(api, "") return swarmhttp.NewServer(api, "")
}, nil) }, nil)
log.Info("starting 1 node cluster") log.Info("starting a test swarm server")
defer srv.Close() defer srv.Close()
// create a private key file for signing // create a private key file for signing
...@@ -65,7 +65,7 @@ func TestCLIResourceUpdate(t *testing.T) { ...@@ -65,7 +65,7 @@ func TestCLIResourceUpdate(t *testing.T) {
} }
// compose a topic. We'll be doing quotes about Miguel de Cervantes // compose a topic. We'll be doing quotes about Miguel de Cervantes
var topic mru.Topic var topic feed.Topic
subject := []byte("Miguel de Cervantes") subject := []byte("Miguel de Cervantes")
copy(topic[:], subject[:]) copy(topic[:], subject[:])
name := "quotes" name := "quotes"
...@@ -77,13 +77,13 @@ func TestCLIResourceUpdate(t *testing.T) { ...@@ -77,13 +77,13 @@ func TestCLIResourceUpdate(t *testing.T) {
flags := []string{ flags := []string{
"--bzzapi", srv.URL, "--bzzapi", srv.URL,
"--bzzaccount", pkfile.Name(), "--bzzaccount", pkfile.Name(),
"resource", "update", "feed", "update",
"--topic", topic.Hex(), "--topic", topic.Hex(),
"--name", name, "--name", name,
hexData} hexData}
// create an update and expect an exit without errors // create an update and expect an exit without errors
log.Info(fmt.Sprintf("updating a resource with 'swarm resource update'")) log.Info(fmt.Sprintf("updating a feed with 'swarm feed update'"))
cmd := runSwarm(t, flags...) cmd := runSwarm(t, flags...)
cmd.ExpectExit() cmd.ExpectExit()
...@@ -95,22 +95,22 @@ func TestCLIResourceUpdate(t *testing.T) { ...@@ -95,22 +95,22 @@ func TestCLIResourceUpdate(t *testing.T) {
// build the same topic as before, this time // build the same topic as before, this time
// we use NewTopic to create a topic automatically. // we use NewTopic to create a topic automatically.
topic, err = mru.NewTopic(name, subject) topic, err = feed.NewTopic(name, subject)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// View configures whose updates we will be looking up. // Feed configures whose updates we will be looking up.
view := mru.View{ fd := feed.Feed{
Topic: topic, Topic: topic,
User: address, User: address,
} }
// Build a query to get the latest update // Build a query to get the latest update
query := mru.NewQueryLatest(&view, lookup.NoClue) query := feed.NewQueryLatest(&fd, lookup.NoClue)
// retrieve content! // retrieve content!
reader, err := client.GetResource(query, "") reader, err := client.QueryFeed(query, "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -128,45 +128,45 @@ func TestCLIResourceUpdate(t *testing.T) { ...@@ -128,45 +128,45 @@ func TestCLIResourceUpdate(t *testing.T) {
// Now retrieve info for the next update // Now retrieve info for the next update
flags = []string{ flags = []string{
"--bzzapi", srv.URL, "--bzzapi", srv.URL,
"resource", "info", "feed", "info",
"--topic", topic.Hex(), "--topic", topic.Hex(),
"--user", address.Hex(), "--user", address.Hex(),
} }
log.Info(fmt.Sprintf("getting resource info with 'swarm resource info'")) log.Info(fmt.Sprintf("getting feed info with 'swarm feed info'"))
cmd = runSwarm(t, flags...) cmd = runSwarm(t, flags...)
_, matches := cmd.ExpectRegexp(`.*`) // regex hack to extract stdout _, matches := cmd.ExpectRegexp(`.*`) // regex hack to extract stdout
cmd.ExpectExit() cmd.ExpectExit()
// verify we can deserialize the result as a valid JSON // verify we can deserialize the result as a valid JSON
var request mru.Request var request feed.Request
err = json.Unmarshal([]byte(matches[0]), &request) err = json.Unmarshal([]byte(matches[0]), &request)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// make sure the retrieved view is the same // make sure the retrieved feed is the same
if request.View != view { if request.Feed != fd {
t.Fatalf("Expected view to be: %s, got %s", view, request.View) t.Fatalf("Expected feed to be: %s, got %s", fd, request.Feed)
} }
// test publishing a manifest // test publishing a manifest
flags = []string{ flags = []string{
"--bzzapi", srv.URL, "--bzzapi", srv.URL,
"--bzzaccount", pkfile.Name(), "--bzzaccount", pkfile.Name(),
"resource", "create", "feed", "create",
"--topic", topic.Hex(), "--topic", topic.Hex(),
} }
log.Info(fmt.Sprintf("Publishing manifest with 'swarm resource create'")) log.Info(fmt.Sprintf("Publishing manifest with 'swarm feed create'"))
cmd = runSwarm(t, flags...) cmd = runSwarm(t, flags...)
_, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) // regex hack to extract stdout _, matches = cmd.ExpectRegexp(`[a-f\d]{64}`) // regex hack to extract stdout
cmd.ExpectExit() cmd.ExpectExit()
manifestAddress := matches[0] // read the received resource manifest manifestAddress := matches[0] // read the received feed manifest
// now attempt to lookup the latest update using a manifest instead // now attempt to lookup the latest update using a manifest instead
reader, err = client.GetResource(nil, manifestAddress) reader, err = client.QueryFeed(nil, manifestAddress)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
...@@ -207,25 +207,25 @@ var ( ...@@ -207,25 +207,25 @@ var (
Name: "compressed", Name: "compressed",
Usage: "Prints encryption keys in compressed form", Usage: "Prints encryption keys in compressed form",
} }
SwarmResourceNameFlag = cli.StringFlag{ SwarmFeedNameFlag = cli.StringFlag{
Name: "name", Name: "name",
Usage: "User-defined name for the new resource, limited to 32 characters. If combined with topic, the resource will be a subtopic with this name", Usage: "User-defined name for the new feed, limited to 32 characters. If combined with topic, it will refer to a subtopic with this name",
} }
SwarmResourceTopicFlag = cli.StringFlag{ SwarmFeedTopicFlag = cli.StringFlag{
Name: "topic", Name: "topic",
Usage: "User-defined topic this resource is tracking, hex encoded. Limited to 64 hexadecimal characters", Usage: "User-defined topic this feed is tracking, hex encoded. Limited to 64 hexadecimal characters",
} }
SwarmResourceDataOnCreateFlag = cli.StringFlag{ SwarmFeedDataOnCreateFlag = cli.StringFlag{
Name: "data", Name: "data",
Usage: "Initializes the resource with the given hex-encoded data. Data must be prefixed by 0x", Usage: "Initializes the feed with the given hex-encoded data. Data must be prefixed by 0x",
} }
SwarmResourceManifestFlag = cli.StringFlag{ SwarmFeedManifestFlag = cli.StringFlag{
Name: "manifest", Name: "manifest",
Usage: "Refers to the resource through a manifest", Usage: "Refers to the feed through a manifest",
} }
SwarmResourceUserFlag = cli.StringFlag{ SwarmFeedUserFlag = cli.StringFlag{
Name: "user", Name: "user",
Usage: "Indicates the user who updates the resource", Usage: "Indicates the user who updates the feed",
} }
) )
...@@ -346,62 +346,62 @@ func init() { ...@@ -346,62 +346,62 @@ func init() {
}, },
{ {
CustomHelpTemplate: helpTemplate, CustomHelpTemplate: helpTemplate,
Name: "resource", Name: "feed",
Usage: "(Advanced) Create and update Mutable Resources", Usage: "(Advanced) Create and update Swarm Feeds",
ArgsUsage: "<create|update|info>", ArgsUsage: "<create|update|info>",
Description: "Works with Mutable Resource Updates", Description: "Works with Swarm Feeds",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Action: resourceCreate, Action: feedCreateManifest,
CustomHelpTemplate: helpTemplate, CustomHelpTemplate: helpTemplate,
Name: "create", Name: "create",
Usage: "creates and publishes a new Mutable Resource manifest", Usage: "creates and publishes a new feed manifest",
Description: `creates and publishes a new Mutable Resource manifest pointing to a specified user's updates about a particular topic. Description: `creates and publishes a new feed manifest pointing to a specified user's updates about a particular topic.
The resource topic can be built in the following ways: The feed topic can be built in the following ways:
* use --topic to set the topic to an arbitrary binary hex string. * use --topic to set the topic to an arbitrary binary hex string.
* use --name to set the topic to a human-readable name. * use --name to set the topic to a human-readable name.
For example --name could be set to "profile-picture", meaning this Mutable Resource allows to get this user's current profile picture. For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture.
* use both --topic and --name to create named subtopics. * use both --topic and --name to create named subtopics.
For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning
the Mutable Resource tracks a discussion about that contract. this feed tracks a discussion about that contract.
The --user flag allows to have this manifest refer to a user other than yourself. If not specified, The --user flag allows to have this manifest refer to a user other than yourself. If not specified,
it will then default to your local account (--bzzaccount)`, it will then default to your local account (--bzzaccount)`,
Flags: []cli.Flag{SwarmResourceNameFlag, SwarmResourceTopicFlag, SwarmResourceUserFlag}, Flags: []cli.Flag{SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag},
}, },
{ {
Action: resourceUpdate, Action: feedUpdate,
CustomHelpTemplate: helpTemplate, CustomHelpTemplate: helpTemplate,
Name: "update", Name: "update",
Usage: "updates the content of an existing Mutable Resource", Usage: "updates the content of an existing Swarm Feed",
ArgsUsage: "<0x Hex data>", ArgsUsage: "<0x Hex data>",
Description: `publishes a new update on the specified topic Description: `publishes a new update on the specified topic
The resource topic can be built in the following ways: The feed topic can be built in the following ways:
* use --topic to set the topic to an arbitrary binary hex string. * use --topic to set the topic to an arbitrary binary hex string.
* use --name to set the topic to a human-readable name. * use --name to set the topic to a human-readable name.
For example --name could be set to "profile-picture", meaning this Mutable Resource allows to get this user's current profile picture. For example --name could be set to "profile-picture", meaning this feed allows to get this user's current profile picture.
* use both --topic and --name to create named subtopics. * use both --topic and --name to create named subtopics.
For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning For example, --topic could be set to an Ethereum contract address and --name could be set to "comments", meaning
the Mutable Resource tracks a discussion about that contract. this feed tracks a discussion about that contract.
If you have a manifest, you can specify it with --manifest to refer to the resource, If you have a manifest, you can specify it with --manifest to refer to the feed,
instead of using --topic / --name instead of using --topic / --name
`, `,
Flags: []cli.Flag{SwarmResourceManifestFlag, SwarmResourceNameFlag, SwarmResourceTopicFlag}, Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag},
}, },
{ {
Action: resourceInfo, Action: feedInfo,
CustomHelpTemplate: helpTemplate, CustomHelpTemplate: helpTemplate,
Name: "info", Name: "info",
Usage: "obtains information about an existing Mutable Resource", Usage: "obtains information about an existing Swarm feed",
Description: `obtains information about an existing Mutable Resource Description: `obtains information about an existing Swarm feed
The topic can be specified directly with the --topic flag as an hex string The topic can be specified directly with the --topic flag as an hex string
If no topic is specified, the default topic (zero) will be used If no topic is specified, the default topic (zero) will be used
The --name flag can be used to specify subtopics with a specific name. The --name flag can be used to specify subtopics with a specific name.
The --user flag allows to refer to a user other than yourself. If not specified, The --user flag allows to refer to a user other than yourself. If not specified,
it will then default to your local account (--bzzaccount) it will then default to your local account (--bzzaccount)
If you have a manifest, you can specify it with --manifest instead of --topic / --name / ---user If you have a manifest, you can specify it with --manifest instead of --topic / --name / ---user
to refer to the resource`, to refer to the feed`,
Flags: []cli.Flag{SwarmResourceManifestFlag, SwarmResourceNameFlag, SwarmResourceTopicFlag, SwarmResourceUserFlag}, Flags: []cli.Flag{SwarmFeedManifestFlag, SwarmFeedNameFlag, SwarmFeedTopicFlag, SwarmFeedUserFlag},
}, },
}, },
}, },
...@@ -730,7 +730,7 @@ func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.Pr ...@@ -730,7 +730,7 @@ func getAccount(bzzaccount string, ctx *cli.Context, stack *node.Node) *ecdsa.Pr
} }
// getPrivKey returns the private key of the specified bzzaccount // getPrivKey returns the private key of the specified bzzaccount
// Used only by client commands, such as `resource` // Used only by client commands, such as `feed`
func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey { func getPrivKey(ctx *cli.Context) *ecdsa.PrivateKey {
// booting up the swarm node just as we do in bzzd action // booting up the swarm node just as we do in bzzd action
bzzconfig, err := buildConfig(ctx) bzzconfig, err := buildConfig(ctx)
......
...@@ -22,5 +22,5 @@ swarm ...@@ -22,5 +22,5 @@ swarm
├── storage ─────────────── ethersphere ├── storage ─────────────── ethersphere
│ ├── encryption ──────── @gbalint, @zelig, @nagydani │ ├── encryption ──────── @gbalint, @zelig, @nagydani
│ ├── mock ────────────── @janos │ ├── mock ────────────── @janos
│ └── mru ─────────────── @nolash │ └── feed ────────────── @nolash, @jpeletier
└── testutil ────────────── @lmars └── testutil ────────────── @lmars
\ No newline at end of file
This diff is collapsed.
...@@ -35,7 +35,7 @@ import ( ...@@ -35,7 +35,7 @@ import (
"strings" "strings"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/storage/mru" "github.com/ethereum/go-ethereum/swarm/storage/feed"
) )
var ( var (
...@@ -601,16 +601,15 @@ func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error) ...@@ -601,16 +601,15 @@ func (c *Client) MultipartUpload(hash string, uploader Uploader) (string, error)
return string(data), nil return string(data), nil
} }
// ErrNoResourceUpdatesFound is returned when Swarm cannot find updates of the given resource // ErrNoFeedUpdatesFound is returned when Swarm cannot find updates of the given feed
var ErrNoResourceUpdatesFound = errors.New("No updates found for this resource") var ErrNoFeedUpdatesFound = errors.New("No updates found for this feed")
// CreateResource creates a Mutable Resource with the given name and frequency, initializing it with the provided // CreateFeedWithManifest creates a feed manifest, initializing it with the provided
// data. Data is interpreted as multihash or not depending on the multihash parameter. // data
// startTime=0 means "now" // Returns the resulting feed manifest address that you can use to include in an ENS Resolver (setContent)
// Returns the resulting Mutable Resource manifest address that you can use to include in an ENS Resolver (setContent) // or reference future updates (Client.UpdateFeed)
// or reference future updates (Client.UpdateResource) func (c *Client) CreateFeedWithManifest(request *feed.Request) (string, error) {
func (c *Client) CreateResource(request *mru.Request) (string, error) { responseStream, err := c.updateFeed(request, true)
responseStream, err := c.updateResource(request, true)
if err != nil { if err != nil {
return "", err return "", err
} }
...@@ -628,18 +627,18 @@ func (c *Client) CreateResource(request *mru.Request) (string, error) { ...@@ -628,18 +627,18 @@ func (c *Client) CreateResource(request *mru.Request) (string, error) {
return manifestAddress, nil return manifestAddress, nil
} }
// UpdateResource allows you to set a new version of your content // UpdateFeed allows you to set a new version of your content
func (c *Client) UpdateResource(request *mru.Request) error { func (c *Client) UpdateFeed(request *feed.Request) error {
_, err := c.updateResource(request, false) _, err := c.updateFeed(request, false)
return err return err
} }
func (c *Client) updateResource(request *mru.Request, createManifest bool) (io.ReadCloser, error) { func (c *Client) updateFeed(request *feed.Request, createManifest bool) (io.ReadCloser, error) {
URL, err := url.Parse(c.Gateway) URL, err := url.Parse(c.Gateway)
if err != nil { if err != nil {
return nil, err return nil, err
} }
URL.Path = "/bzz-resource:/" URL.Path = "/bzz-feed:/"
values := URL.Query() values := URL.Query()
body := request.AppendValues(values) body := request.AppendValues(values)
if createManifest { if createManifest {
...@@ -660,23 +659,23 @@ func (c *Client) updateResource(request *mru.Request, createManifest bool) (io.R ...@@ -660,23 +659,23 @@ func (c *Client) updateResource(request *mru.Request, createManifest bool) (io.R
return res.Body, nil return res.Body, nil
} }
// GetResource returns a byte stream with the raw content of the resource // QueryFeed returns a byte stream with the raw content of the feed update
// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver // manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver
// points to that address // points to that address
func (c *Client) GetResource(query *mru.Query, manifestAddressOrDomain string) (io.ReadCloser, error) { func (c *Client) QueryFeed(query *feed.Query, manifestAddressOrDomain string) (io.ReadCloser, error) {
return c.getResource(query, manifestAddressOrDomain, false) return c.queryFeed(query, manifestAddressOrDomain, false)
} }
// getResource returns a byte stream with the raw content of the resource // queryFeed returns a byte stream with the raw content of the feed update
// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver // manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver
// points to that address // points to that address
// meta set to true will instruct the node return resource metainformation instead // meta set to true will instruct the node return feed metainformation instead
func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, meta bool) (io.ReadCloser, error) { func (c *Client) queryFeed(query *feed.Query, manifestAddressOrDomain string, meta bool) (io.ReadCloser, error) {
URL, err := url.Parse(c.Gateway) URL, err := url.Parse(c.Gateway)
if err != nil { if err != nil {
return nil, err return nil, err
} }
URL.Path = "/bzz-resource:/" + manifestAddressOrDomain URL.Path = "/bzz-feed:/" + manifestAddressOrDomain
values := URL.Query() values := URL.Query()
if query != nil { if query != nil {
query.AppendValues(values) //adds query parameters query.AppendValues(values) //adds query parameters
...@@ -692,7 +691,7 @@ func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, m ...@@ -692,7 +691,7 @@ func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, m
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
if res.StatusCode == http.StatusNotFound { if res.StatusCode == http.StatusNotFound {
return nil, ErrNoResourceUpdatesFound return nil, ErrNoFeedUpdatesFound
} }
errorMessageBytes, err := ioutil.ReadAll(res.Body) errorMessageBytes, err := ioutil.ReadAll(res.Body)
var errorMessage string var errorMessage string
...@@ -701,18 +700,18 @@ func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, m ...@@ -701,18 +700,18 @@ func (c *Client) getResource(query *mru.Query, manifestAddressOrDomain string, m
} else { } else {
errorMessage = string(errorMessageBytes) errorMessage = string(errorMessageBytes)
} }
return nil, fmt.Errorf("Error retrieving resource: %s", errorMessage) return nil, fmt.Errorf("Error retrieving feed updates: %s", errorMessage)
} }
return res.Body, nil return res.Body, nil
} }
// GetResourceMetadata returns a structure that describes the Mutable Resource // GetFeedRequest returns a structure that describes the referenced feed status
// manifestAddressOrDomain is the address you obtained in CreateResource or an ENS domain whose Resolver // manifestAddressOrDomain is the address you obtained in CreateFeedWithManifest or an ENS domain whose Resolver
// points to that address // points to that address
func (c *Client) GetResourceMetadata(query *mru.Query, manifestAddressOrDomain string) (*mru.Request, error) { func (c *Client) GetFeedRequest(query *feed.Query, manifestAddressOrDomain string) (*feed.Request, error) {
responseStream, err := c.getResource(query, manifestAddressOrDomain, true) responseStream, err := c.queryFeed(query, manifestAddressOrDomain, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -723,7 +722,7 @@ func (c *Client) GetResourceMetadata(query *mru.Query, manifestAddressOrDomain s ...@@ -723,7 +722,7 @@ func (c *Client) GetResourceMetadata(query *mru.Query, manifestAddressOrDomain s
return nil, err return nil, err
} }
var metadata mru.Request var metadata feed.Request
if err := metadata.UnmarshalJSON(body); err != nil { if err := metadata.UnmarshalJSON(body); err != nil {
return nil, err return nil, err
} }
......
...@@ -25,14 +25,14 @@ import ( ...@@ -25,14 +25,14 @@ import (
"sort" "sort"
"testing" "testing"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http"
"github.com/ethereum/go-ethereum/swarm/multihash" "github.com/ethereum/go-ethereum/swarm/multihash"
"github.com/ethereum/go-ethereum/swarm/storage/mru" "github.com/ethereum/go-ethereum/swarm/storage/feed"
"github.com/ethereum/go-ethereum/swarm/testutil" "github.com/ethereum/go-ethereum/swarm/testutil"
) )
...@@ -361,20 +361,20 @@ func TestClientMultipartUpload(t *testing.T) { ...@@ -361,20 +361,20 @@ func TestClientMultipartUpload(t *testing.T) {
} }
} }
func newTestSigner() (*mru.GenericSigner, error) { func newTestSigner() (*feed.GenericSigner, error) {
privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
if err != nil { if err != nil {
return nil, err return nil, err
} }
return mru.NewGenericSigner(privKey), nil return feed.NewGenericSigner(privKey), nil
} }
// test the transparent resolving of multihash resource types with bzz:// scheme // test the transparent resolving of multihash feed updates with bzz:// scheme
// //
// first upload data, and store the multihash to the resulting manifest in a resource update // 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 // retrieving the update with the multihash should return the manifest pointing directly to the data
// and raw retrieve of that hash should return the data // and raw retrieve of that hash should return the data
func TestClientCreateResourceMultihash(t *testing.T) { func TestClientCreateFeedMultihash(t *testing.T) {
signer, _ := newTestSigner() signer, _ := newTestSigner()
...@@ -393,36 +393,36 @@ func TestClientCreateResourceMultihash(t *testing.T) { ...@@ -393,36 +393,36 @@ func TestClientCreateResourceMultihash(t *testing.T) {
s := common.FromHex(swarmHash) s := common.FromHex(swarmHash)
mh := multihash.ToMultihash(s) mh := multihash.ToMultihash(s)
// our mutable resource topic // our feed topic
topic, _ := mru.NewTopic("foo.eth", nil) topic, _ := feed.NewTopic("foo.eth", nil)
createRequest := mru.NewFirstRequest(topic) createRequest := feed.NewFirstRequest(topic)
createRequest.SetData(mh) createRequest.SetData(mh)
if err := createRequest.Sign(signer); err != nil { if err := createRequest.Sign(signer); err != nil {
t.Fatalf("Error signing update: %s", err) t.Fatalf("Error signing update: %s", err)
} }
resourceManifestHash, err := client.CreateResource(createRequest) feedManifestHash, err := client.CreateFeedWithManifest(createRequest)
if err != nil { if err != nil {
t.Fatalf("Error creating resource: %s", err) t.Fatalf("Error creating feed manifest: %s", err)
} }
correctManifestAddrHex := "6ef40ba1492cf2a029dc9a8b5896c822cf689d3cd010842f4f1744e6db8824bd" correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b"
if resourceManifestHash != correctManifestAddrHex { if feedManifestHash != correctManifestAddrHex {
t.Fatalf("Response resource manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, resourceManifestHash) t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash)
} }
// Check we get a not found error when trying to get the resource with a made-up manifest // Check we get a not found error when trying to get feed updates with a made-up manifest
_, err = client.GetResource(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") _, err = client.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
if err != ErrNoResourceUpdatesFound { if err != ErrNoFeedUpdatesFound {
t.Fatalf("Expected to receive ErrNoResourceUpdatesFound error. Got: %s", err) t.Fatalf("Expected to receive ErrNoFeedUpdatesFound error. Got: %s", err)
} }
reader, err := client.GetResource(nil, correctManifestAddrHex) reader, err := client.QueryFeed(nil, correctManifestAddrHex)
if err != nil { if err != nil {
t.Fatalf("Error retrieving resource: %s", err) t.Fatalf("Error retrieving feed updates: %s", err)
} }
defer reader.Close() defer reader.Close()
gotData, err := ioutil.ReadAll(reader) gotData, err := ioutil.ReadAll(reader)
...@@ -435,8 +435,8 @@ func TestClientCreateResourceMultihash(t *testing.T) { ...@@ -435,8 +435,8 @@ func TestClientCreateResourceMultihash(t *testing.T) {
} }
// TestClientCreateUpdateResource will check that mutable resources can be created and updated via the HTTP client. // TestClientCreateUpdateFeed will check that feeds can be created and updated via the HTTP client.
func TestClientCreateUpdateResource(t *testing.T) { func TestClientCreateUpdateFeed(t *testing.T) {
signer, _ := newTestSigner() signer, _ := newTestSigner()
...@@ -444,28 +444,28 @@ func TestClientCreateUpdateResource(t *testing.T) { ...@@ -444,28 +444,28 @@ func TestClientCreateUpdateResource(t *testing.T) {
client := NewClient(srv.URL) client := NewClient(srv.URL)
defer srv.Close() defer srv.Close()
// set raw data for the resource // set raw data for the feed update
databytes := []byte("En un lugar de La Mancha, de cuyo nombre no quiero acordarme...") databytes := []byte("En un lugar de La Mancha, de cuyo nombre no quiero acordarme...")
// our mutable resource name // our feed topic name
topic, _ := mru.NewTopic("El Quijote", nil) topic, _ := feed.NewTopic("El Quijote", nil)
createRequest := mru.NewFirstRequest(topic) createRequest := feed.NewFirstRequest(topic)
createRequest.SetData(databytes) createRequest.SetData(databytes)
if err := createRequest.Sign(signer); err != nil { if err := createRequest.Sign(signer); err != nil {
t.Fatalf("Error signing update: %s", err) t.Fatalf("Error signing update: %s", err)
} }
resourceManifestHash, err := client.CreateResource(createRequest) feedManifestHash, err := client.CreateFeedWithManifest(createRequest)
correctManifestAddrHex := "fcb8e75f53e480e197c083ad1976d265674d0ce776f2bf359c09c413fb5230b8" correctManifestAddrHex := "0e9b645ebc3da167b1d56399adc3276f7a08229301b72a03336be0e7d4b71882"
if resourceManifestHash != correctManifestAddrHex { if feedManifestHash != correctManifestAddrHex {
t.Fatalf("Response resource manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, resourceManifestHash) t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash)
} }
reader, err := client.GetResource(nil, correctManifestAddrHex) reader, err := client.QueryFeed(nil, correctManifestAddrHex)
if err != nil { if err != nil {
t.Fatalf("Error retrieving resource: %s", err) t.Fatalf("Error retrieving feed updates: %s", err)
} }
defer reader.Close() defer reader.Close()
gotData, err := ioutil.ReadAll(reader) gotData, err := ioutil.ReadAll(reader)
...@@ -479,7 +479,7 @@ func TestClientCreateUpdateResource(t *testing.T) { ...@@ -479,7 +479,7 @@ func TestClientCreateUpdateResource(t *testing.T) {
// define different data // define different data
databytes = []byte("... no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero ...") databytes = []byte("... no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero ...")
updateRequest, err := client.GetResourceMetadata(nil, correctManifestAddrHex) updateRequest, err := client.GetFeedRequest(nil, correctManifestAddrHex)
if err != nil { if err != nil {
t.Fatalf("Error retrieving update request template: %s", err) t.Fatalf("Error retrieving update request template: %s", err)
} }
...@@ -489,13 +489,13 @@ func TestClientCreateUpdateResource(t *testing.T) { ...@@ -489,13 +489,13 @@ func TestClientCreateUpdateResource(t *testing.T) {
t.Fatalf("Error signing update: %s", err) t.Fatalf("Error signing update: %s", err)
} }
if err = client.UpdateResource(updateRequest); err != nil { if err = client.UpdateFeed(updateRequest); err != nil {
t.Fatalf("Error updating resource: %s", err) t.Fatalf("Error updating feed: %s", err)
} }
reader, err = client.GetResource(nil, correctManifestAddrHex) reader, err = client.QueryFeed(nil, correctManifestAddrHex)
if err != nil { if err != nil {
t.Fatalf("Error retrieving resource: %s", err) t.Fatalf("Error retrieving feed updates: %s", err)
} }
defer reader.Close() defer reader.Close()
gotData, err = ioutil.ReadAll(reader) gotData, err = ioutil.ReadAll(reader)
...@@ -506,17 +506,17 @@ func TestClientCreateUpdateResource(t *testing.T) { ...@@ -506,17 +506,17 @@ func TestClientCreateUpdateResource(t *testing.T) {
t.Fatalf("Expected: %v, got %v", databytes, gotData) t.Fatalf("Expected: %v, got %v", databytes, gotData)
} }
// now try retrieving resource without a manifest // now try retrieving feed updates without a manifest
view := &mru.View{ fd := &feed.Feed{
Topic: topic, Topic: topic,
User: signer.Address(), User: signer.Address(),
} }
lookupParams := mru.NewQueryLatest(view, lookup.NoClue) lookupParams := feed.NewQueryLatest(fd, lookup.NoClue)
reader, err = client.GetResource(lookupParams, "") reader, err = client.QueryFeed(lookupParams, "")
if err != nil { if err != nil {
t.Fatalf("Error retrieving resource: %s", err) t.Fatalf("Error retrieving feed updates: %s", err)
} }
defer reader.Close() defer reader.Close()
gotData, err = ioutil.ReadAll(reader) gotData, err = ioutil.ReadAll(reader)
......
This diff is collapsed.
This diff is collapsed.
...@@ -27,7 +27,7 @@ import ( ...@@ -27,7 +27,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/ethereum/go-ethereum/swarm/storage/mru" "github.com/ethereum/go-ethereum/swarm/storage/feed"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/log"
...@@ -35,8 +35,8 @@ import ( ...@@ -35,8 +35,8 @@ import (
) )
const ( const (
ManifestType = "application/bzz-manifest+json" ManifestType = "application/bzz-manifest+json"
ResourceContentType = "application/bzz-resource" FeedContentType = "application/bzz-feed"
manifestSizeLimit = 5 * 1024 * 1024 manifestSizeLimit = 5 * 1024 * 1024
) )
...@@ -48,15 +48,15 @@ type Manifest struct { ...@@ -48,15 +48,15 @@ type Manifest struct {
// ManifestEntry represents an entry in a swarm manifest // ManifestEntry represents an entry in a swarm manifest
type ManifestEntry struct { type ManifestEntry struct {
Hash string `json:"hash,omitempty"` Hash string `json:"hash,omitempty"`
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
ContentType string `json:"contentType,omitempty"` ContentType string `json:"contentType,omitempty"`
Mode int64 `json:"mode,omitempty"` Mode int64 `json:"mode,omitempty"`
Size int64 `json:"size,omitempty"` Size int64 `json:"size,omitempty"`
ModTime time.Time `json:"mod_time,omitempty"` ModTime time.Time `json:"mod_time,omitempty"`
Status int `json:"status,omitempty"` Status int `json:"status,omitempty"`
Access *AccessEntry `json:"access,omitempty"` Access *AccessEntry `json:"access,omitempty"`
ResourceView *mru.View `json:"resourceView,omitempty"` Feed *feed.Feed `json:"feed,omitempty"`
} }
// ManifestList represents the result of listing files in a manifest // ManifestList represents the result of listing files in a manifest
...@@ -80,13 +80,13 @@ func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address, ...@@ -80,13 +80,13 @@ func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address,
return addr, err return addr, err
} }
// Manifest hack for supporting Mutable Resource Updates from the bzz: scheme // Manifest hack for supporting Swarm feeds from the bzz: scheme
// see swarm/api/api.go:API.Get() for more information // see swarm/api/api.go:API.Get() for more information
func (a *API) NewResourceManifest(ctx context.Context, view *mru.View) (storage.Address, error) { func (a *API) NewFeedManifest(ctx context.Context, feed *feed.Feed) (storage.Address, error) {
var manifest Manifest var manifest Manifest
entry := ManifestEntry{ entry := ManifestEntry{
ResourceView: view, Feed: feed,
ContentType: ResourceContentType, ContentType: FeedContentType,
} }
manifest.Entries = append(manifest.Entries, entry) manifest.Entries = append(manifest.Entries, entry)
data, err := json.Marshal(&manifest) data, err := json.Marshal(&manifest)
......
...@@ -86,7 +86,7 @@ func Parse(rawuri string) (*URI, error) { ...@@ -86,7 +86,7 @@ func Parse(rawuri string) (*URI, error) {
// check the scheme is valid // check the scheme is valid
switch uri.Scheme { switch uri.Scheme {
case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-resource": case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-feed":
default: default:
return nil, fmt.Errorf("unknown scheme %q", u.Scheme) return nil, fmt.Errorf("unknown scheme %q", u.Scheme)
} }
...@@ -108,8 +108,8 @@ func Parse(rawuri string) (*URI, error) { ...@@ -108,8 +108,8 @@ func Parse(rawuri string) (*URI, error) {
} }
return uri, nil return uri, nil
} }
func (u *URI) Resource() bool { func (u *URI) Feed() bool {
return u.Scheme == "bzz-resource" return u.Scheme == "bzz-feed"
} }
func (u *URI) Raw() bool { func (u *URI) Raw() bool {
......
...@@ -37,7 +37,7 @@ Using the streamer logic, various stream types are easy to implement: ...@@ -37,7 +37,7 @@ Using the streamer logic, various stream types are easy to implement:
* live session syncing * live session syncing
* historical syncing * historical syncing
* simple retrieve requests and deliveries * simple retrieve requests and deliveries
* mutable resource updates streams * swarm feeds streams
* receipting for finger pointing * receipting for finger pointing
## Syncing ## Syncing
...@@ -57,7 +57,7 @@ receipts for a deleted chunk easily to refute their challenge. ...@@ -57,7 +57,7 @@ receipts for a deleted chunk easily to refute their challenge.
- syncing should be resilient to cut connections, metadata should be persisted that - syncing should be resilient to cut connections, metadata should be persisted that
keep track of syncing state across sessions, historical syncing state should survive restart keep track of syncing state across sessions, historical syncing state should survive restart
- extra data structures to support syncing should be kept at minimum - extra data structures to support syncing should be kept at minimum
- syncing is organized separately for chunk types (resource update v content chunk) - syncing is not organized separately for chunk types (Swarm feed updates v regular content chunk)
- various types of streams should have common logic abstracted - various types of streams should have common logic abstracted
Syncing is now entirely mediated by the localstore, ie., no processes or memory leaks due to network contention. Syncing is now entirely mediated by the localstore, ie., no processes or memory leaks due to network contention.
......
...@@ -317,7 +317,7 @@ func (c *Controller) handleStartMsg(msg *Msg, keyid string) (err error) { ...@@ -317,7 +317,7 @@ func (c *Controller) handleStartMsg(msg *Msg, keyid string) (err error) {
return err return err
} }
// TODO this is set to zero-length byte pending decision on protocol for initial message, whether it should include message or not, and how to trigger the initial message so that current state of MRU is sent upon subscription // TODO this is set to zero-length byte pending decision on protocol for initial message, whether it should include message or not, and how to trigger the initial message so that current state of Swarm feed is sent upon subscription
notify := []byte{} notify := []byte{}
replyMsg := NewMsg(MsgCodeNotifyWithKey, msg.namestring, make([]byte, len(notify)+symKeyLength)) replyMsg := NewMsg(MsgCodeNotifyWithKey, msg.namestring, make([]byte, len(notify)+symKeyLength))
copy(replyMsg.Payload, notify) copy(replyMsg.Payload, notify)
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import "github.com/ethereum/go-ethereum/common/hexutil" import "github.com/ethereum/go-ethereum/common/hexutil"
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"encoding/json" "encoding/json"
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"bytes" "bytes"
...@@ -26,23 +26,23 @@ import ( ...@@ -26,23 +26,23 @@ import (
const ( const (
hasherCount = 8 hasherCount = 8
resourceHashAlgorithm = storage.SHA3Hash feedsHashAlgorithm = storage.SHA3Hash
defaultRetrieveTimeout = 100 * time.Millisecond defaultRetrieveTimeout = 100 * time.Millisecond
) )
// cacheEntry caches resource data and the metadata of its root chunk. // cacheEntry caches the last known update of a specific Swarm feed.
type cacheEntry struct { type cacheEntry struct {
ResourceUpdate Update
*bytes.Reader *bytes.Reader
lastKey storage.Address lastKey storage.Address
} }
// implements storage.LazySectionReader // implements storage.LazySectionReader
func (r *cacheEntry) Size(ctx context.Context, _ chan bool) (int64, error) { func (r *cacheEntry) Size(ctx context.Context, _ chan bool) (int64, error) {
return int64(len(r.ResourceUpdate.data)), nil return int64(len(r.Update.data)), nil
} }
//returns the resource's topic //returns the feed's topic
func (r *cacheEntry) Topic() Topic { func (r *cacheEntry) Topic() Topic {
return r.View.Topic return r.Feed.Topic
} }
/* /*
Package mru defines Mutable resource updates. Package feeds defines Swarm Feeds.
A Mutable Resource is an entity which allows updates to a resource Swarm Feeds allows a user to build an update feed about a particular topic
without resorting to ENS on each update. without resorting to ENS on each update.
The update scheme is built on swarm chunks with chunk keys following The update scheme is built on swarm chunks with chunk keys following
a predictable, versionable pattern. a predictable, versionable pattern.
A Resource is tied to a unique identifier that is deterministically generated out of A Feed is tied to a unique identifier that is deterministically generated out of
the chosen topic. the chosen topic.
A Resource View is defined as a specific user's point of view about a particular resource. A Feed is defined as the series of updates of a specific user about a particular topic
Thus, a View is a Topic + the user's address (userAddr)
Actual data updates are also made in the form of swarm chunks. The keys Actual data updates are also made in the form of swarm chunks. The keys
of the updates are the hash of a concatenation of properties as follows: of the updates are the hash of a concatenation of properties as follows:
updateAddr = H(View, Epoch ID) updateAddr = H(Feed, Epoch ID)
where H is the SHA3 hash function where H is the SHA3 hash function
View is the combination of Topic and the user address Feed is the combination of Topic and the user address
Epoch ID is a time slot. See the lookup package for more information. Epoch ID is a time slot. See the lookup package for more information.
A user looking up a resource would only need to know the View in order to A user looking up a the latest update in a Feed only needs to know the Topic
another user's updates and the other user's address.
The resource update data is: The Feed Update data is:
resourcedata = View|Epoch|data updatedata = Feed|Epoch|data
the full update data that goes in the chunk payload is: The full update data that goes in the chunk payload is:
resourcedata|sign(resourcedata) updatedata|sign(updatedata)
Structure Summary: Structure Summary:
Request: Resource update with signature Request: Feed Update with signature
ResourceUpdate: headers + data Update: headers + data
Header: Protocol version and reserved for future use placeholders Header: Protocol version and reserved for future use placeholders
ID: Information about how to locate a specific update ID: Information about how to locate a specific update
View: Author of the update and what is updating Feed: Represents a user's series of publications about a specific Topic
Topic: Item that the updates are about Topic: Item that the updates are about
User: User who updates the resource User: User who updates the Feed
Epoch: time slot where the update is stored Epoch: time slot where the update is stored
*/ */
package mru package feed
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"fmt" "fmt"
...@@ -35,7 +35,7 @@ const ( ...@@ -35,7 +35,7 @@ const (
ErrCnt ErrCnt
) )
// Error is a the typed error object used for Mutable Resources // Error is a the typed error object used for Swarm feeds
type Error struct { type Error struct {
code int code int
err string err string
...@@ -47,12 +47,12 @@ func (e *Error) Error() string { ...@@ -47,12 +47,12 @@ func (e *Error) Error() string {
} }
// Code returns the error code // Code returns the error code
// Error codes are enumerated in the error.go file within the mru package // Error codes are enumerated in the error.go file within the feeds package
func (e *Error) Code() int { func (e *Error) Code() int {
return e.code return e.code
} }
// NewError creates a new Mutable Resource Error object with the specified code and custom error message // NewError creates a new Swarm feeds Error object with the specified code and custom error message
func NewError(code int, s string) error { func NewError(code int, s string) error {
if code < 0 || code >= ErrCnt { if code < 0 || code >= ErrCnt {
panic("no such error code!") panic("no such error code!")
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"hash" "hash"
...@@ -25,21 +25,21 @@ import ( ...@@ -25,21 +25,21 @@ import (
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
) )
// View represents a particular user's view of a resource // Feed represents a particular user's stream of updates on a topic
type View struct { type Feed struct {
Topic Topic `json:"topic"` Topic Topic `json:"topic"`
User common.Address `json:"user"` User common.Address `json:"user"`
} }
// View layout: // Feed layout:
// TopicLength bytes // TopicLength bytes
// userAddr common.AddressLength bytes // userAddr common.AddressLength bytes
const viewLength = TopicLength + common.AddressLength const feedLength = TopicLength + common.AddressLength
// mapKey calculates a unique id for this view for the cache map in `Handler` // mapKey calculates a unique id for this feed. Used by the cache map in `Handler`
func (u *View) mapKey() uint64 { func (f *Feed) mapKey() uint64 {
serializedData := make([]byte, viewLength) serializedData := make([]byte, feedLength)
u.binaryPut(serializedData) f.binaryPut(serializedData)
hasher := hashPool.Get().(hash.Hash) hasher := hashPool.Get().(hash.Hash)
defer hashPool.Put(hasher) defer hashPool.Put(hasher)
hasher.Reset() hasher.Reset()
...@@ -48,55 +48,55 @@ func (u *View) mapKey() uint64 { ...@@ -48,55 +48,55 @@ func (u *View) mapKey() uint64 {
return *(*uint64)(unsafe.Pointer(&hash[0])) return *(*uint64)(unsafe.Pointer(&hash[0]))
} }
// binaryPut serializes this View instance into the provided slice // binaryPut serializes this feed instance into the provided slice
func (u *View) binaryPut(serializedData []byte) error { func (f *Feed) binaryPut(serializedData []byte) error {
if len(serializedData) != viewLength { if len(serializedData) != feedLength {
return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize View. Expected %d, got %d", viewLength, len(serializedData)) return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize feed. Expected %d, got %d", feedLength, len(serializedData))
} }
var cursor int var cursor int
copy(serializedData[cursor:cursor+TopicLength], u.Topic[:TopicLength]) copy(serializedData[cursor:cursor+TopicLength], f.Topic[:TopicLength])
cursor += TopicLength cursor += TopicLength
copy(serializedData[cursor:cursor+common.AddressLength], u.User[:]) copy(serializedData[cursor:cursor+common.AddressLength], f.User[:])
cursor += common.AddressLength cursor += common.AddressLength
return nil return nil
} }
// binaryLength returns the expected size of this structure when serialized // binaryLength returns the expected size of this structure when serialized
func (u *View) binaryLength() int { func (f *Feed) binaryLength() int {
return viewLength return feedLength
} }
// binaryGet restores the current instance from the information contained in the passed slice // binaryGet restores the current instance from the information contained in the passed slice
func (u *View) binaryGet(serializedData []byte) error { func (f *Feed) binaryGet(serializedData []byte) error {
if len(serializedData) != viewLength { if len(serializedData) != feedLength {
return NewErrorf(ErrInvalidValue, "Incorrect slice size to read View. Expected %d, got %d", viewLength, len(serializedData)) return NewErrorf(ErrInvalidValue, "Incorrect slice size to read feed. Expected %d, got %d", feedLength, len(serializedData))
} }
var cursor int var cursor int
copy(u.Topic[:], serializedData[cursor:cursor+TopicLength]) copy(f.Topic[:], serializedData[cursor:cursor+TopicLength])
cursor += TopicLength cursor += TopicLength
copy(u.User[:], serializedData[cursor:cursor+common.AddressLength]) copy(f.User[:], serializedData[cursor:cursor+common.AddressLength])
cursor += common.AddressLength cursor += common.AddressLength
return nil return nil
} }
// Hex serializes the View to a hex string // Hex serializes the feed to a hex string
func (u *View) Hex() string { func (f *Feed) Hex() string {
serializedData := make([]byte, viewLength) serializedData := make([]byte, feedLength)
u.binaryPut(serializedData) f.binaryPut(serializedData)
return hexutil.Encode(serializedData) return hexutil.Encode(serializedData)
} }
// FromValues deserializes this instance from a string key-value store // FromValues deserializes this instance from a string key-value store
// useful to parse query strings // useful to parse query strings
func (u *View) FromValues(values Values) (err error) { func (f *Feed) FromValues(values Values) (err error) {
topic := values.Get("topic") topic := values.Get("topic")
if topic != "" { if topic != "" {
if err := u.Topic.FromHex(values.Get("topic")); err != nil { if err := f.Topic.FromHex(values.Get("topic")); err != nil {
return err return err
} }
} else { // see if the user set name and relatedcontent } else { // see if the user set name and relatedcontent
...@@ -108,18 +108,18 @@ func (u *View) FromValues(values Values) (err error) { ...@@ -108,18 +108,18 @@ func (u *View) FromValues(values Values) (err error) {
} }
relatedContent = relatedContent[:storage.AddressLength] relatedContent = relatedContent[:storage.AddressLength]
} }
u.Topic, err = NewTopic(name, relatedContent) f.Topic, err = NewTopic(name, relatedContent)
if err != nil { if err != nil {
return err return err
} }
} }
u.User = common.HexToAddress(values.Get("user")) f.User = common.HexToAddress(values.Get("user"))
return nil return nil
} }
// AppendValues serializes this structure into the provided string key-value store // AppendValues serializes this structure into the provided string key-value store
// useful to build query strings // useful to build query strings
func (u *View) AppendValues(values Values) { func (f *Feed) AppendValues(values Values) {
values.Set("topic", u.Topic.Hex()) values.Set("topic", f.Topic.Hex())
values.Set("user", u.User.Hex()) values.Set("user", f.User.Hex())
} }
...@@ -13,24 +13,24 @@ ...@@ -13,24 +13,24 @@
// //
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"testing" "testing"
) )
func getTestView() *View { func getTestFeed() *Feed {
topic, _ := NewTopic("world news report, every hour", nil) topic, _ := NewTopic("world news report, every hour", nil)
return &View{ return &Feed{
Topic: topic, Topic: topic,
User: newCharlieSigner().Address(), User: newCharlieSigner().Address(),
} }
} }
func TestViewSerializerDeserializer(t *testing.T) { func TestFeedSerializerDeserializer(t *testing.T) {
testBinarySerializerRecovery(t, getTestView(), "0x776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781c") testBinarySerializerRecovery(t, getTestFeed(), "0x776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781c")
} }
func TestMetadataSerializerLengthCheck(t *testing.T) { func TestFeedSerializerLengthCheck(t *testing.T) {
testBinarySerializerLengthCheck(t, getTestView()) testBinarySerializerLengthCheck(t, getTestFeed())
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"fmt" "fmt"
...@@ -22,28 +22,28 @@ import ( ...@@ -22,28 +22,28 @@ import (
"strconv" "strconv"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
) )
// ID uniquely identifies an update on the network. // ID uniquely identifies an update on the network.
type ID struct { type ID struct {
View `json:"view"` Feed `json:"feed"`
lookup.Epoch `json:"epoch"` lookup.Epoch `json:"epoch"`
} }
// ID layout: // ID layout:
// View viewLength bytes // Feed feedLength bytes
// Epoch EpochLength // Epoch EpochLength
const idLength = viewLength + lookup.EpochLength const idLength = feedLength + lookup.EpochLength
// Addr calculates the resource update chunk address corresponding to this ID // Addr calculates the feed update chunk address corresponding to this ID
func (u *ID) Addr() (updateAddr storage.Address) { func (u *ID) Addr() (updateAddr storage.Address) {
serializedData := make([]byte, idLength) serializedData := make([]byte, idLength)
var cursor int var cursor int
u.View.binaryPut(serializedData[cursor : cursor+viewLength]) u.Feed.binaryPut(serializedData[cursor : cursor+feedLength])
cursor += viewLength cursor += feedLength
eid := u.Epoch.ID() eid := u.Epoch.ID()
copy(serializedData[cursor:cursor+lookup.EpochLength], eid[:]) copy(serializedData[cursor:cursor+lookup.EpochLength], eid[:])
...@@ -61,10 +61,10 @@ func (u *ID) binaryPut(serializedData []byte) error { ...@@ -61,10 +61,10 @@ func (u *ID) binaryPut(serializedData []byte) error {
return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize ID. Expected %d, got %d", idLength, len(serializedData)) return NewErrorf(ErrInvalidValue, "Incorrect slice size to serialize ID. Expected %d, got %d", idLength, len(serializedData))
} }
var cursor int var cursor int
if err := u.View.binaryPut(serializedData[cursor : cursor+viewLength]); err != nil { if err := u.Feed.binaryPut(serializedData[cursor : cursor+feedLength]); err != nil {
return err return err
} }
cursor += viewLength cursor += feedLength
epochBytes, err := u.Epoch.MarshalBinary() epochBytes, err := u.Epoch.MarshalBinary()
if err != nil { if err != nil {
...@@ -88,10 +88,10 @@ func (u *ID) binaryGet(serializedData []byte) error { ...@@ -88,10 +88,10 @@ func (u *ID) binaryGet(serializedData []byte) error {
} }
var cursor int var cursor int
if err := u.View.binaryGet(serializedData[cursor : cursor+viewLength]); err != nil { if err := u.Feed.binaryGet(serializedData[cursor : cursor+feedLength]); err != nil {
return err return err
} }
cursor += viewLength cursor += feedLength
if err := u.Epoch.UnmarshalBinary(serializedData[cursor : cursor+lookup.EpochLength]); err != nil { if err := u.Epoch.UnmarshalBinary(serializedData[cursor : cursor+lookup.EpochLength]); err != nil {
return err return err
...@@ -108,8 +108,8 @@ func (u *ID) FromValues(values Values) error { ...@@ -108,8 +108,8 @@ func (u *ID) FromValues(values Values) error {
u.Epoch.Level = uint8(level) u.Epoch.Level = uint8(level)
u.Epoch.Time, _ = strconv.ParseUint(values.Get("time"), 10, 64) u.Epoch.Time, _ = strconv.ParseUint(values.Get("time"), 10, 64)
if u.View.User == (common.Address{}) { if u.Feed.User == (common.Address{}) {
return u.View.FromValues(values) return u.Feed.FromValues(values)
} }
return nil return nil
} }
...@@ -119,5 +119,5 @@ func (u *ID) FromValues(values Values) error { ...@@ -119,5 +119,5 @@ func (u *ID) FromValues(values Values) error {
func (u *ID) AppendValues(values Values) { func (u *ID) AppendValues(values Values) {
values.Set("level", fmt.Sprintf("%d", u.Epoch.Level)) values.Set("level", fmt.Sprintf("%d", u.Epoch.Level))
values.Set("time", fmt.Sprintf("%d", u.Epoch.Time)) values.Set("time", fmt.Sprintf("%d", u.Epoch.Time))
u.View.AppendValues(values) u.Feed.AppendValues(values)
} }
package mru package feed
import ( import (
"testing" "testing"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
) )
func getTestID() *ID { func getTestID() *ID {
return &ID{ return &ID{
View: *getTestView(), Feed: *getTestFeed(),
Epoch: lookup.GetFirstEpoch(1000), Epoch: lookup.GetFirstEpoch(1000),
} }
} }
func TestIDAddr(t *testing.T) { func TestIDAddr(t *testing.T) {
ul := getTestID() id := getTestID()
updateAddr := ul.Addr() updateAddr := id.Addr()
compareByteSliceToExpectedHex(t, "updateAddr", updateAddr, "0x8b24583ec293e085f4c78aaee66d1bc5abfb8b4233304d14a349afa57af2a783") compareByteSliceToExpectedHex(t, "updateAddr", updateAddr, "0x8b24583ec293e085f4c78aaee66d1bc5abfb8b4233304d14a349afa57af2a783")
} }
......
...@@ -3,7 +3,7 @@ package lookup_test ...@@ -3,7 +3,7 @@ package lookup_test
import ( import (
"testing" "testing"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
) )
func TestMarshallers(t *testing.T) { func TestMarshallers(t *testing.T) {
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
/* /*
Package lookup defines resource lookup algorithms and provides tools to place updates Package lookup defines feed lookup algorithms and provides tools to place updates
so they can be found so they can be found
*/ */
package lookup package lookup
......
...@@ -22,7 +22,7 @@ import ( ...@@ -22,7 +22,7 @@ import (
"testing" "testing"
"github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/log"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
) )
type Data struct { type Data struct {
......
...@@ -14,20 +14,20 @@ ...@@ -14,20 +14,20 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
) )
// Query is used to specify constraints when performing an update lookup // Query is used to specify constraints when performing an update lookup
// TimeLimit indicates an upper bound for the search. Set to 0 for "now" // TimeLimit indicates an upper bound for the search. Set to 0 for "now"
type Query struct { type Query struct {
View Feed
Hint lookup.Epoch Hint lookup.Epoch
TimeLimit uint64 TimeLimit uint64
} }
...@@ -41,8 +41,8 @@ func (q *Query) FromValues(values Values) error { ...@@ -41,8 +41,8 @@ func (q *Query) FromValues(values Values) error {
level, _ := strconv.ParseUint(values.Get("hint.level"), 10, 32) level, _ := strconv.ParseUint(values.Get("hint.level"), 10, 32)
q.Hint.Level = uint8(level) q.Hint.Level = uint8(level)
q.Hint.Time, _ = strconv.ParseUint(values.Get("hint.time"), 10, 64) q.Hint.Time, _ = strconv.ParseUint(values.Get("hint.time"), 10, 64)
if q.View.User == (common.Address{}) { if q.Feed.User == (common.Address{}) {
return q.View.FromValues(values) return q.Feed.FromValues(values)
} }
return nil return nil
} }
...@@ -59,20 +59,20 @@ func (q *Query) AppendValues(values Values) { ...@@ -59,20 +59,20 @@ func (q *Query) AppendValues(values Values) {
if q.Hint.Time != 0 { if q.Hint.Time != 0 {
values.Set("hint.time", fmt.Sprintf("%d", q.Hint.Time)) values.Set("hint.time", fmt.Sprintf("%d", q.Hint.Time))
} }
q.View.AppendValues(values) q.Feed.AppendValues(values)
} }
// NewQuery constructs an Query structure to find updates on or before `time` // NewQuery constructs an Query structure to find updates on or before `time`
// if time == 0, the latest update will be looked up // if time == 0, the latest update will be looked up
func NewQuery(view *View, time uint64, hint lookup.Epoch) *Query { func NewQuery(feed *Feed, time uint64, hint lookup.Epoch) *Query {
return &Query{ return &Query{
TimeLimit: time, TimeLimit: time,
View: *view, Feed: *feed,
Hint: hint, Hint: hint,
} }
} }
// NewQueryLatest generates lookup parameters that look for the latest version of a resource // NewQueryLatest generates lookup parameters that look for the latest update to a feed
func NewQueryLatest(view *View, hint lookup.Epoch) *Query { func NewQueryLatest(feed *Feed, hint lookup.Epoch) *Query {
return NewQuery(view, 0, hint) return NewQuery(feed, 0, hint)
} }
...@@ -14,18 +14,18 @@ ...@@ -14,18 +14,18 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"testing" "testing"
) )
func getTestQuery() *Query { func getTestQuery() *Query {
ul := getTestID() id := getTestID()
return &Query{ return &Query{
TimeLimit: 5000, TimeLimit: 5000,
View: ul.View, Feed: id.Feed,
Hint: ul.Epoch, Hint: id.Epoch,
} }
} }
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"bytes" "bytes"
...@@ -24,15 +24,15 @@ import ( ...@@ -24,15 +24,15 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
) )
// Request represents an update and/or resource create message // Request represents a request to sign or signed feed update message
type Request struct { type Request struct {
ResourceUpdate // actual content that will be put on the chunk, less signature Update // actual content that will be put on the chunk, less signature
Signature *Signature Signature *Signature
idAddr storage.Address // cached chunk address for the update (not serialized, for internal use) idAddr storage.Address // cached chunk address for the update (not serialized, for internal use)
binaryData []byte // cached serialized data (does not get serialized again!, for efficiency/internal use) binaryData []byte // cached serialized data (does not get serialized again!, for efficiency/internal use)
} }
// updateRequestJSON represents a JSON-serialized UpdateRequest // updateRequestJSON represents a JSON-serialized UpdateRequest
...@@ -44,11 +44,11 @@ type updateRequestJSON struct { ...@@ -44,11 +44,11 @@ type updateRequestJSON struct {
} }
// Request layout // Request layout
// resourceUpdate bytes // Update bytes
// SignatureLength bytes // SignatureLength bytes
const minimumSignedUpdateLength = minimumUpdateDataLength + signatureLength const minimumSignedUpdateLength = minimumUpdateDataLength + signatureLength
// NewFirstRequest returns a ready to sign request to publish a first update // NewFirstRequest returns a ready to sign request to publish a first feed update
func NewFirstRequest(topic Topic) *Request { func NewFirstRequest(topic Topic) *Request {
request := new(Request) request := new(Request)
...@@ -56,13 +56,13 @@ func NewFirstRequest(topic Topic) *Request { ...@@ -56,13 +56,13 @@ func NewFirstRequest(topic Topic) *Request {
// get the current time // get the current time
now := TimestampProvider.Now().Time now := TimestampProvider.Now().Time
request.Epoch = lookup.GetFirstEpoch(now) request.Epoch = lookup.GetFirstEpoch(now)
request.View.Topic = topic request.Feed.Topic = topic
request.Header.Version = ProtocolVersion request.Header.Version = ProtocolVersion
return request return request
} }
// SetData stores the payload data the resource will be updated with // SetData stores the payload data the feed update will be updated with
func (r *Request) SetData(data []byte) { func (r *Request) SetData(data []byte) {
r.data = data r.data = data
r.Signature = nil r.Signature = nil
...@@ -73,7 +73,7 @@ func (r *Request) IsUpdate() bool { ...@@ -73,7 +73,7 @@ func (r *Request) IsUpdate() bool {
return r.Signature != nil return r.Signature != nil
} }
// Verify checks that signatures are valid and that the signer owns the resource to be updated // Verify checks that signatures are valid
func (r *Request) Verify() (err error) { func (r *Request) Verify() (err error) {
if len(r.data) == 0 { if len(r.data) == 0 {
return NewError(ErrInvalidValue, "Update does not contain data") return NewError(ErrInvalidValue, "Update does not contain data")
...@@ -88,7 +88,7 @@ func (r *Request) Verify() (err error) { ...@@ -88,7 +88,7 @@ func (r *Request) Verify() (err error) {
} }
// get the address of the signer (which also checks that it's a valid signature) // get the address of the signer (which also checks that it's a valid signature)
r.View.User, err = getUserAddr(digest, *r.Signature) r.Feed.User, err = getUserAddr(digest, *r.Signature)
if err != nil { if err != nil {
return err return err
} }
...@@ -103,9 +103,9 @@ func (r *Request) Verify() (err error) { ...@@ -103,9 +103,9 @@ func (r *Request) Verify() (err error) {
return nil return nil
} }
// Sign executes the signature to validate the resource // Sign executes the signature to validate the update message
func (r *Request) Sign(signer Signer) error { func (r *Request) Sign(signer Signer) error {
r.View.User = signer.Address() r.Feed.User = signer.Address()
r.binaryData = nil //invalidate serialized data r.binaryData = nil //invalidate serialized data
digest, err := r.GetDigest() // computes digest and serializes into .binaryData digest, err := r.GetDigest() // computes digest and serializes into .binaryData
if err != nil { if err != nil {
...@@ -133,16 +133,16 @@ func (r *Request) Sign(signer Signer) error { ...@@ -133,16 +133,16 @@ func (r *Request) Sign(signer Signer) error {
return nil return nil
} }
// GetDigest creates the resource update digest used in signatures // GetDigest creates the feed update digest used in signatures
// the serialized payload is cached in .binaryData // the serialized payload is cached in .binaryData
func (r *Request) GetDigest() (result common.Hash, err error) { func (r *Request) GetDigest() (result common.Hash, err error) {
hasher := hashPool.Get().(hash.Hash) hasher := hashPool.Get().(hash.Hash)
defer hashPool.Put(hasher) defer hashPool.Put(hasher)
hasher.Reset() hasher.Reset()
dataLength := r.ResourceUpdate.binaryLength() dataLength := r.Update.binaryLength()
if r.binaryData == nil { if r.binaryData == nil {
r.binaryData = make([]byte, dataLength+signatureLength) r.binaryData = make([]byte, dataLength+signatureLength)
if err := r.ResourceUpdate.binaryPut(r.binaryData[:dataLength]); err != nil { if err := r.Update.binaryPut(r.binaryData[:dataLength]); err != nil {
return result, err return result, err
} }
} }
...@@ -161,10 +161,10 @@ func (r *Request) toChunk() (storage.Chunk, error) { ...@@ -161,10 +161,10 @@ func (r *Request) toChunk() (storage.Chunk, error) {
return nil, NewError(ErrInvalidSignature, "toChunk called without a valid signature or payload data. Call .Sign() first.") return nil, NewError(ErrInvalidSignature, "toChunk called without a valid signature or payload data. Call .Sign() first.")
} }
resourceUpdateLength := r.ResourceUpdate.binaryLength() updateLength := r.Update.binaryLength()
// signature is the last item in the chunk data // signature is the last item in the chunk data
copy(r.binaryData[resourceUpdateLength:], r.Signature[:]) copy(r.binaryData[updateLength:], r.Signature[:])
chunk := storage.NewChunk(r.idAddr, r.binaryData) chunk := storage.NewChunk(r.idAddr, r.binaryData)
return chunk, nil return chunk, nil
...@@ -174,14 +174,14 @@ func (r *Request) toChunk() (storage.Chunk, error) { ...@@ -174,14 +174,14 @@ func (r *Request) toChunk() (storage.Chunk, error) {
func (r *Request) fromChunk(updateAddr storage.Address, chunkdata []byte) error { func (r *Request) fromChunk(updateAddr storage.Address, chunkdata []byte) error {
// for update chunk layout see Request definition // for update chunk layout see Request definition
//deserialize the resource update portion //deserialize the feed update portion
if err := r.ResourceUpdate.binaryGet(chunkdata[:len(chunkdata)-signatureLength]); err != nil { if err := r.Update.binaryGet(chunkdata[:len(chunkdata)-signatureLength]); err != nil {
return err return err
} }
// Extract the signature // Extract the signature
var signature *Signature var signature *Signature
cursor := r.ResourceUpdate.binaryLength() cursor := r.Update.binaryLength()
sigdata := chunkdata[cursor : cursor+signatureLength] sigdata := chunkdata[cursor : cursor+signatureLength]
if len(sigdata) > 0 { if len(sigdata) > 0 {
signature = &Signature{} signature = &Signature{}
...@@ -209,7 +209,7 @@ func (r *Request) FromValues(values Values, data []byte) error { ...@@ -209,7 +209,7 @@ func (r *Request) FromValues(values Values, data []byte) error {
r.Signature = new(Signature) r.Signature = new(Signature)
copy(r.Signature[:], signatureBytes) copy(r.Signature[:], signatureBytes)
} }
err = r.ResourceUpdate.FromValues(values, data) err = r.Update.FromValues(values, data)
if err != nil { if err != nil {
return err return err
} }
...@@ -223,7 +223,7 @@ func (r *Request) AppendValues(values Values) []byte { ...@@ -223,7 +223,7 @@ func (r *Request) AppendValues(values Values) []byte {
if r.Signature != nil { if r.Signature != nil {
values.Set("signature", hexutil.Encode(r.Signature[:])) values.Set("signature", hexutil.Encode(r.Signature[:]))
} }
return r.ResourceUpdate.AppendValues(values) return r.Update.AppendValues(values)
} }
// fromJSON takes an update request JSON and populates an UpdateRequest // fromJSON takes an update request JSON and populates an UpdateRequest
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"bytes" "bytes"
...@@ -26,7 +26,7 @@ import ( ...@@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/storage/mru/lookup" "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
) )
func areEqualJSON(s1, s2 string) (bool, error) { func areEqualJSON(s1, s2 string) (bool, error) {
...@@ -47,51 +47,49 @@ func areEqualJSON(s1, s2 string) (bool, error) { ...@@ -47,51 +47,49 @@ func areEqualJSON(s1, s2 string) (bool, error) {
} }
// TestEncodingDecodingUpdateRequests ensures that requests are serialized properly // TestEncodingDecodingUpdateRequests ensures that requests are serialized properly
// while also checking cryptographically that only the owner of a resource can update it. // while also checking cryptographically that only the owner of a feed can update it.
func TestEncodingDecodingUpdateRequests(t *testing.T) { func TestEncodingDecodingUpdateRequests(t *testing.T) {
charlie := newCharlieSigner() //Charlie charlie := newCharlieSigner() //Charlie
bob := newBobSigner() //Bob bob := newBobSigner() //Bob
// Create a resource to our good guy Charlie's name // Create a feed to our good guy Charlie's name
topic, _ := NewTopic("a good resource name", nil) topic, _ := NewTopic("a good topic name", nil)
createRequest := NewFirstRequest(topic) firstRequest := NewFirstRequest(topic)
createRequest.User = charlie.Address() firstRequest.User = charlie.Address()
// We now encode the create message to simulate we send it over the wire // We now encode the create message to simulate we send it over the wire
messageRawData, err := createRequest.MarshalJSON() messageRawData, err := firstRequest.MarshalJSON()
if err != nil { if err != nil {
t.Fatalf("Error encoding create resource request: %s", err) t.Fatalf("Error encoding first feed update request: %s", err)
} }
// ... the message arrives and is decoded... // ... the message arrives and is decoded...
var recoveredCreateRequest Request var recoveredFirstRequest Request
if err := recoveredCreateRequest.UnmarshalJSON(messageRawData); err != nil { if err := recoveredFirstRequest.UnmarshalJSON(messageRawData); err != nil {
t.Fatalf("Error decoding create resource request: %s", err) t.Fatalf("Error decoding first feed update request: %s", err)
} }
// ... but verification should fail because it is not signed! // ... but verification should fail because it is not signed!
if err := recoveredCreateRequest.Verify(); err == nil { if err := recoveredFirstRequest.Verify(); err == nil {
t.Fatal("Expected Verify to fail since the message is not signed") t.Fatal("Expected Verify to fail since the message is not signed")
} }
// We now assume that the resource was created and propagated. With rootAddr we can retrieve the resource metadata // We now assume that the feed ypdate was created and propagated.
// and recover the information above. To sign an update, we need the rootAddr and the metaHash to construct
// proof of ownership
const expectedSignature = "0x32c2d2c7224e24e4d3ae6a10595fc6e945f1b3ecdf548a04d8247c240a50c9240076aa7730abad6c8a46dfea00cfb8f43b6211f02db5c4cc5ed8584cb0212a4d00" const expectedSignature = "0x7235b27a68372ddebcf78eba48543fa460864b0b0e99cb533fcd3664820e603312d29426dd00fb39628f5299480a69bf6e462838d78de49ce0704c754c9deb2601"
const expectedJSON = `{"view":{"topic":"0x6120676f6f64207265736f75726365206e616d65000000000000000000000000","user":"0x876a8936a7cd0b79ef0735ad0896c1afe278781c"},"epoch":{"time":1000,"level":1},"protocolVersion":0,"data":"0x5468697320686f75722773207570646174653a20537761726d2039392e3020686173206265656e2072656c656173656421"}` const expectedJSON = `{"feed":{"topic":"0x6120676f6f6420746f706963206e616d65000000000000000000000000000000","user":"0x876a8936a7cd0b79ef0735ad0896c1afe278781c"},"epoch":{"time":1000,"level":1},"protocolVersion":0,"data":"0x5468697320686f75722773207570646174653a20537761726d2039392e3020686173206265656e2072656c656173656421"}`
//Put together an unsigned update request that we will serialize to send it to the signer. //Put together an unsigned update request that we will serialize to send it to the signer.
data := []byte("This hour's update: Swarm 99.0 has been released!") data := []byte("This hour's update: Swarm 99.0 has been released!")
request := &Request{ request := &Request{
ResourceUpdate: ResourceUpdate{ Update: Update{
ID: ID{ ID: ID{
Epoch: lookup.Epoch{ Epoch: lookup.Epoch{
Time: 1000, Time: 1000,
Level: 1, Level: 1,
}, },
View: createRequest.ResourceUpdate.View, Feed: firstRequest.Update.Feed,
}, },
data: data, data: data,
}, },
...@@ -138,7 +136,7 @@ func TestEncodingDecodingUpdateRequests(t *testing.T) { ...@@ -138,7 +136,7 @@ func TestEncodingDecodingUpdateRequests(t *testing.T) {
t.Fatal("Expected DecodeUpdateRequest to fail when trying to interpret a corrupt message with an invalid signature") t.Fatal("Expected DecodeUpdateRequest to fail when trying to interpret a corrupt message with an invalid signature")
} }
// Now imagine Bob wants to create an update of his own about the same resource, // Now imagine Bob wants to create an update of his own about the same feed,
// signing a message with his private key // signing a message with his private key
if err := request.Sign(bob); err != nil { if err := request.Sign(bob); err != nil {
t.Fatalf("Error signing: %s", err) t.Fatalf("Error signing: %s", err)
...@@ -191,7 +189,7 @@ func TestEncodingDecodingUpdateRequests(t *testing.T) { ...@@ -191,7 +189,7 @@ func TestEncodingDecodingUpdateRequests(t *testing.T) {
func getTestRequest() *Request { func getTestRequest() *Request {
return &Request{ return &Request{
ResourceUpdate: *getTestResourceUpdate(), Update: *getTestFeedUpdate(),
} }
} }
...@@ -230,7 +228,7 @@ func TestUpdateChunkSerializationErrorChecking(t *testing.T) { ...@@ -230,7 +228,7 @@ func TestUpdateChunkSerializationErrorChecking(t *testing.T) {
var recovered Request var recovered Request
recovered.fromChunk(chunk.Address(), chunk.Data()) recovered.fromChunk(chunk.Address(), chunk.Data())
if !reflect.DeepEqual(recovered, r) { if !reflect.DeepEqual(recovered, r) {
t.Fatal("Expected recovered SignedResource update to equal the original one") t.Fatal("Expected recovered feed update request to equal the original one")
} }
} }
...@@ -250,7 +248,7 @@ func TestReverse(t *testing.T) { ...@@ -250,7 +248,7 @@ func TestReverse(t *testing.T) {
// signer containing private key // signer containing private key
signer := newAliceSigner() signer := newAliceSigner()
// set up rpc and create resourcehandler // set up rpc and create feeds handler
_, _, teardownTest, err := setupTest(timeProvider, signer) _, _, teardownTest, err := setupTest(timeProvider, signer)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -258,7 +256,7 @@ func TestReverse(t *testing.T) { ...@@ -258,7 +256,7 @@ func TestReverse(t *testing.T) {
defer teardownTest() defer teardownTest()
topic, _ := NewTopic("Cervantes quotes", nil) topic, _ := NewTopic("Cervantes quotes", nil)
view := View{ fd := Feed{
Topic: topic, Topic: topic,
User: signer.Address(), User: signer.Address(),
} }
...@@ -266,7 +264,7 @@ func TestReverse(t *testing.T) { ...@@ -266,7 +264,7 @@ func TestReverse(t *testing.T) {
data := []byte("Donde una puerta se cierra, otra se abre") data := []byte("Donde una puerta se cierra, otra se abre")
request := new(Request) request := new(Request)
request.View = view request.Feed = fd
request.Epoch = epoch request.Epoch = epoch
request.data = data request.data = data
...@@ -291,15 +289,15 @@ func TestReverse(t *testing.T) { ...@@ -291,15 +289,15 @@ func TestReverse(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
recoveredaddress, err := getUserAddr(checkdigest, *checkUpdate.Signature) recoveredAddr, err := getUserAddr(checkdigest, *checkUpdate.Signature)
if err != nil { if err != nil {
t.Fatalf("Retrieve address from signature fail: %v", err) t.Fatalf("Retrieve address from signature fail: %v", err)
} }
originaladdress := crypto.PubkeyToAddress(signer.PrivKey.PublicKey) originalAddr := crypto.PubkeyToAddress(signer.PrivKey.PublicKey)
// check that the metadata retrieved from the chunk matches what we gave it // check that the metadata retrieved from the chunk matches what we gave it
if recoveredaddress != originaladdress { if recoveredAddr != originalAddr {
t.Fatalf("addresses dont match: %x != %x", originaladdress, recoveredaddress) t.Fatalf("addresses dont match: %x != %x", originalAddr, recoveredAddr)
} }
if !bytes.Equal(key[:], chunk.Address()[:]) { if !bytes.Equal(key[:], chunk.Address()[:]) {
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
...@@ -28,7 +28,7 @@ const signatureLength = 65 ...@@ -28,7 +28,7 @@ const signatureLength = 65
// Signature is an alias for a static byte array with the size of a signature // Signature is an alias for a static byte array with the size of a signature
type Signature [signatureLength]byte type Signature [signatureLength]byte
// Signer signs Mutable Resource update payloads // Signer signs feed update payloads
type Signer interface { type Signer interface {
Sign(common.Hash) (Signature, error) Sign(common.Hash) (Signature, error)
Address() common.Address Address() common.Address
...@@ -65,7 +65,7 @@ func (s *GenericSigner) Address() common.Address { ...@@ -65,7 +65,7 @@ func (s *GenericSigner) Address() common.Address {
return s.address return s.address
} }
// getUserAddr extracts the address of the resource update signer // getUserAddr extracts the address of the feed update signer
func getUserAddr(digest common.Hash, signature Signature) (common.Address, error) { func getUserAddr(digest common.Hash, signature Signature) (common.Address, error) {
pub, err := crypto.SigToPub(digest.Bytes(), signature[:]) pub, err := crypto.SigToPub(digest.Bytes(), signature[:])
if err != nil { if err != nil {
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"context" "context"
...@@ -27,7 +27,7 @@ import ( ...@@ -27,7 +27,7 @@ import (
) )
const ( const (
testDbDirName = "mru" testDbDirName = "feeds"
) )
type TestHandler struct { type TestHandler struct {
...@@ -52,20 +52,20 @@ func newFakeNetFetcher(context.Context, storage.Address, *sync.Map) storage.NetF ...@@ -52,20 +52,20 @@ func newFakeNetFetcher(context.Context, storage.Address, *sync.Map) storage.NetF
// NewTestHandler creates Handler object to be used for testing purposes. // NewTestHandler creates Handler object to be used for testing purposes.
func NewTestHandler(datadir string, params *HandlerParams) (*TestHandler, error) { func NewTestHandler(datadir string, params *HandlerParams) (*TestHandler, error) {
path := filepath.Join(datadir, testDbDirName) path := filepath.Join(datadir, testDbDirName)
rh := NewHandler(params) fh := NewHandler(params)
localstoreparams := storage.NewDefaultLocalStoreParams() localstoreparams := storage.NewDefaultLocalStoreParams()
localstoreparams.Init(path) localstoreparams.Init(path)
localStore, err := storage.NewLocalStore(localstoreparams, nil) localStore, err := storage.NewLocalStore(localstoreparams, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("localstore create fail, path %s: %v", path, err) return nil, fmt.Errorf("localstore create fail, path %s: %v", path, err)
} }
localStore.Validators = append(localStore.Validators, storage.NewContentAddressValidator(storage.MakeHashFunc(resourceHashAlgorithm))) localStore.Validators = append(localStore.Validators, storage.NewContentAddressValidator(storage.MakeHashFunc(feedsHashAlgorithm)))
localStore.Validators = append(localStore.Validators, rh) localStore.Validators = append(localStore.Validators, fh)
netStore, err := storage.NewNetStore(localStore, nil) netStore, err := storage.NewNetStore(localStore, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
netStore.NewNetFetcherFunc = newFakeNetFetcher netStore.NewNetFetcherFunc = newFakeNetFetcher
rh.SetStore(netStore) fh.SetStore(netStore)
return &TestHandler{rh}, nil return &TestHandler{fh}, nil
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"encoding/binary" "encoding/binary"
...@@ -22,7 +22,7 @@ import ( ...@@ -22,7 +22,7 @@ import (
"time" "time"
) )
// TimestampProvider sets the time source of the mru package // TimestampProvider sets the time source of the feeds package
var TimestampProvider timestampProvider = NewDefaultTimestampProvider() var TimestampProvider timestampProvider = NewDefaultTimestampProvider()
// Timestamp encodes a point in time as a Unix epoch // Timestamp encodes a point in time as a Unix epoch
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"bytes" "bytes"
...@@ -29,7 +29,7 @@ import ( ...@@ -29,7 +29,7 @@ import (
// TopicLength establishes the max length of a topic string // TopicLength establishes the max length of a topic string
const TopicLength = storage.AddressLength const TopicLength = storage.AddressLength
// Topic represents what a resource talks about // Topic represents what a feed is about
type Topic [TopicLength]byte type Topic [TopicLength]byte
// ErrTopicTooLong is returned when creating a topic with a name/related content too long // ErrTopicTooLong is returned when creating a topic with a name/related content too long
...@@ -74,7 +74,7 @@ func (t *Topic) FromHex(hex string) error { ...@@ -74,7 +74,7 @@ func (t *Topic) FromHex(hex string) error {
return nil return nil
} }
// Name will try to extract the resource name out of the topic // Name will try to extract the topic name out of the Topic
func (t *Topic) Name(relatedContent []byte) string { func (t *Topic) Name(relatedContent []byte) string {
nameBytes := *t nameBytes := *t
if relatedContent != nil { if relatedContent != nil {
......
package mru package feed
import ( import (
"testing" "testing"
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"fmt" "fmt"
...@@ -34,25 +34,25 @@ type Header struct { ...@@ -34,25 +34,25 @@ type Header struct {
Padding [headerLength - 1]uint8 // reserved for future use Padding [headerLength - 1]uint8 // reserved for future use
} }
// ResourceUpdate encapsulates the information sent as part of a resource update // Update encapsulates the information sent as part of a feed update
type ResourceUpdate struct { type Update struct {
Header Header // Header Header //
ID // Resource update identifying information ID // Feed Update identifying information
data []byte // actual data payload data []byte // actual data payload
} }
const minimumUpdateDataLength = idLength + headerLength + 1 const minimumUpdateDataLength = idLength + headerLength + 1
const maxUpdateDataLength = chunk.DefaultSize - signatureLength - idLength - headerLength const maxUpdateDataLength = chunk.DefaultSize - signatureLength - idLength - headerLength
// binaryPut serializes the resource update information into the given slice // binaryPut serializes the feed update information into the given slice
func (r *ResourceUpdate) binaryPut(serializedData []byte) error { func (r *Update) binaryPut(serializedData []byte) error {
datalength := len(r.data) datalength := len(r.data)
if datalength == 0 { if datalength == 0 {
return NewError(ErrInvalidValue, "cannot update a resource with no data") return NewError(ErrInvalidValue, "a feed update must contain data")
} }
if datalength > maxUpdateDataLength { if datalength > maxUpdateDataLength {
return NewErrorf(ErrInvalidValue, "data is too big (length=%d). Max length=%d", datalength, maxUpdateDataLength) return NewErrorf(ErrInvalidValue, "feed update data is too big (length=%d). Max length=%d", datalength, maxUpdateDataLength)
} }
if len(serializedData) != r.binaryLength() { if len(serializedData) != r.binaryLength() {
...@@ -79,14 +79,14 @@ func (r *ResourceUpdate) binaryPut(serializedData []byte) error { ...@@ -79,14 +79,14 @@ func (r *ResourceUpdate) binaryPut(serializedData []byte) error {
} }
// binaryLength returns the expected number of bytes this structure will take to encode // binaryLength returns the expected number of bytes this structure will take to encode
func (r *ResourceUpdate) binaryLength() int { func (r *Update) binaryLength() int {
return idLength + headerLength + len(r.data) return idLength + headerLength + len(r.data)
} }
// binaryGet populates this instance from the information contained in the passed byte slice // binaryGet populates this instance from the information contained in the passed byte slice
func (r *ResourceUpdate) binaryGet(serializedData []byte) error { func (r *Update) binaryGet(serializedData []byte) error {
if len(serializedData) < minimumUpdateDataLength { if len(serializedData) < minimumUpdateDataLength {
return NewErrorf(ErrNothingToReturn, "chunk less than %d bytes cannot be a resource update chunk", minimumUpdateDataLength) return NewErrorf(ErrNothingToReturn, "chunk less than %d bytes cannot be a feed update chunk", minimumUpdateDataLength)
} }
dataLength := len(serializedData) - idLength - headerLength dataLength := len(serializedData) - idLength - headerLength
// at this point we can be satisfied that we have the correct data length to read // at this point we can be satisfied that we have the correct data length to read
...@@ -116,7 +116,7 @@ func (r *ResourceUpdate) binaryGet(serializedData []byte) error { ...@@ -116,7 +116,7 @@ func (r *ResourceUpdate) binaryGet(serializedData []byte) error {
// FromValues deserializes this instance from a string key-value store // FromValues deserializes this instance from a string key-value store
// useful to parse query strings // useful to parse query strings
func (r *ResourceUpdate) FromValues(values Values, data []byte) error { func (r *Update) FromValues(values Values, data []byte) error {
r.data = data r.data = data
version, _ := strconv.ParseUint(values.Get("protocolVersion"), 10, 32) version, _ := strconv.ParseUint(values.Get("protocolVersion"), 10, 32)
r.Header.Version = uint8(version) r.Header.Version = uint8(version)
...@@ -125,7 +125,7 @@ func (r *ResourceUpdate) FromValues(values Values, data []byte) error { ...@@ -125,7 +125,7 @@ func (r *ResourceUpdate) FromValues(values Values, data []byte) error {
// AppendValues serializes this structure into the provided string key-value store // AppendValues serializes this structure into the provided string key-value store
// useful to build query strings // useful to build query strings
func (r *ResourceUpdate) AppendValues(values Values) []byte { func (r *Update) AppendValues(values Values) []byte {
r.ID.AppendValues(values) r.ID.AppendValues(values)
values.Set("protocolVersion", fmt.Sprintf("%d", r.Header.Version)) values.Set("protocolVersion", fmt.Sprintf("%d", r.Header.Version))
return r.data return r.data
......
...@@ -14,37 +14,37 @@ ...@@ -14,37 +14,37 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package mru package feed
import ( import (
"testing" "testing"
) )
func getTestResourceUpdate() *ResourceUpdate { func getTestFeedUpdate() *Update {
return &ResourceUpdate{ return &Update{
ID: *getTestID(), ID: *getTestID(),
data: []byte("El que lee mucho y anda mucho, ve mucho y sabe mucho"), data: []byte("El que lee mucho y anda mucho, ve mucho y sabe mucho"),
} }
} }
func TestResourceUpdateSerializer(t *testing.T) { func TestUpdateSerializer(t *testing.T) {
testBinarySerializerRecovery(t, getTestResourceUpdate(), "0x0000000000000000776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce803000000000019456c20717565206c6565206d7563686f207920616e6461206d7563686f2c207665206d7563686f20792073616265206d7563686f") testBinarySerializerRecovery(t, getTestFeedUpdate(), "0x0000000000000000776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce803000000000019456c20717565206c6565206d7563686f207920616e6461206d7563686f2c207665206d7563686f20792073616265206d7563686f")
} }
func TestResourceUpdateLengthCheck(t *testing.T) { func TestUpdateLengthCheck(t *testing.T) {
testBinarySerializerLengthCheck(t, getTestResourceUpdate()) testBinarySerializerLengthCheck(t, getTestFeedUpdate())
// Test fail if update is too big // Test fail if update is too big
update := getTestResourceUpdate() update := getTestFeedUpdate()
update.data = make([]byte, maxUpdateDataLength+100) update.data = make([]byte, maxUpdateDataLength+100)
serialized := make([]byte, update.binaryLength()) serialized := make([]byte, update.binaryLength())
if err := update.binaryPut(serialized); err == nil { if err := update.binaryPut(serialized); err == nil {
t.Fatal("Expected resourceUpdate.binaryPut to fail since update is too big") t.Fatal("Expected update.binaryPut to fail since update is too big")
} }
// test fail if data is empty or nil // test fail if data is empty or nil
update.data = nil update.data = nil
serialized = make([]byte, update.binaryLength()) serialized = make([]byte, update.binaryLength())
if err := update.binaryPut(serialized); err == nil { if err := update.binaryPut(serialized); err == nil {
t.Fatal("Expected resourceUpdate.binaryPut to fail since data is empty") t.Fatal("Expected update.binaryPut to fail since data is empty")
} }
} }
...@@ -30,8 +30,8 @@ var ( ...@@ -30,8 +30,8 @@ var (
) )
// tests that the content address validator correctly checks the data // tests that the content address validator correctly checks the data
// tests that resource update chunks are passed through content address validator // tests that feed update chunks are passed through content address validator
// the test checking the resouce update validator internal correctness is found in resource_test.go // the test checking the resouce update validator internal correctness is found in storage/feeds/handler_test.go
func TestValidator(t *testing.T) { func TestValidator(t *testing.T) {
// set up localstore // set up localstore
datadir, err := ioutil.TempDir("", "storage-testvalidator") datadir, err := ioutil.TempDir("", "storage-testvalidator")
......
...@@ -49,8 +49,8 @@ import ( ...@@ -49,8 +49,8 @@ import (
"github.com/ethereum/go-ethereum/swarm/pss" "github.com/ethereum/go-ethereum/swarm/pss"
"github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/state"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/storage/feed"
"github.com/ethereum/go-ethereum/swarm/storage/mock" "github.com/ethereum/go-ethereum/swarm/storage/mock"
"github.com/ethereum/go-ethereum/swarm/storage/mru"
"github.com/ethereum/go-ethereum/swarm/tracing" "github.com/ethereum/go-ethereum/swarm/tracing"
) )
...@@ -186,15 +186,15 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e ...@@ -186,15 +186,15 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e
// Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage // Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage
self.fileStore = storage.NewFileStore(self.netStore, self.config.FileStoreParams) self.fileStore = storage.NewFileStore(self.netStore, self.config.FileStoreParams)
var resourceHandler *mru.Handler var feedsHandler *feed.Handler
rhparams := &mru.HandlerParams{} fhParams := &feed.HandlerParams{}
resourceHandler = mru.NewHandler(rhparams) feedsHandler = feed.NewHandler(fhParams)
resourceHandler.SetStore(self.netStore) feedsHandler.SetStore(self.netStore)
lstore.Validators = []storage.ChunkValidator{ lstore.Validators = []storage.ChunkValidator{
storage.NewContentAddressValidator(storage.MakeHashFunc(storage.DefaultHash)), storage.NewContentAddressValidator(storage.MakeHashFunc(storage.DefaultHash)),
resourceHandler, feedsHandler,
} }
err = lstore.Migrate() err = lstore.Migrate()
...@@ -215,7 +215,7 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e ...@@ -215,7 +215,7 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e
pss.SetHandshakeController(self.ps, pss.NewHandshakeParams()) pss.SetHandshakeController(self.ps, pss.NewHandshakeParams())
} }
self.api = api.NewAPI(self.fileStore, self.dns, resourceHandler, self.privateKey) self.api = api.NewAPI(self.fileStore, self.dns, feedsHandler, self.privateKey)
self.sfs = fuse.NewSwarmFS(self.api) self.sfs = fuse.NewSwarmFS(self.api)
log.Debug("Initialized FUSE filesystem") log.Debug("Initialized FUSE filesystem")
......
...@@ -25,7 +25,7 @@ import ( ...@@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/storage/mru" "github.com/ethereum/go-ethereum/swarm/storage/feed"
) )
type TestServer interface { type TestServer interface {
...@@ -48,14 +48,14 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso ...@@ -48,14 +48,14 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso
} }
fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams()) fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams())
// mutable resources test setup // Swarm feeds test setup
resourceDir, err := ioutil.TempDir("", "swarm-resource-test") feedsDir, err := ioutil.TempDir("", "swarm-feeds-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
rhparams := &mru.HandlerParams{} rhparams := &feed.HandlerParams{}
rh, err := mru.NewTestHandler(resourceDir, rhparams) rh, err := feed.NewTestHandler(feedsDir, rhparams)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -71,11 +71,11 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso ...@@ -71,11 +71,11 @@ func NewTestSwarmServer(t *testing.T, serverFunc func(*api.API) TestServer, reso
srv.Close() srv.Close()
rh.Close() rh.Close()
os.RemoveAll(dir) os.RemoveAll(dir)
os.RemoveAll(resourceDir) os.RemoveAll(feedsDir)
}, },
CurrentTime: 42, CurrentTime: 42,
} }
mru.TimestampProvider = tss feed.TimestampProvider = tss
return tss return tss
} }
...@@ -92,6 +92,6 @@ func (t *TestSwarmServer) Close() { ...@@ -92,6 +92,6 @@ func (t *TestSwarmServer) Close() {
t.cleanup() t.cleanup()
} }
func (t *TestSwarmServer) Now() mru.Timestamp { func (t *TestSwarmServer) Now() feed.Timestamp {
return mru.Timestamp{Time: t.CurrentTime} return feed.Timestamp{Time: t.CurrentTime}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment