From acfca335caf1a414ee23cdf69f93671a1cb8f5e3 Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Wed, 12 Apr 2023 10:29:37 +0200 Subject: [PATCH 1/4] feat(routing): allow-offline with routing put --- coreiface/options/routing.go | 35 +++++++++++++++++++++++++++++++++++ coreiface/routing.go | 4 +++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 coreiface/options/routing.go diff --git a/coreiface/options/routing.go b/coreiface/options/routing.go new file mode 100644 index 000000000..d66d44a0d --- /dev/null +++ b/coreiface/options/routing.go @@ -0,0 +1,35 @@ +package options + +type RoutingPutSettings struct { + AllowOffline bool +} + +type RoutingPutOption func(*RoutingPutSettings) error + +func RoutingPutOptions(opts ...RoutingPutOption) (*RoutingPutSettings, error) { + options := &RoutingPutSettings{ + AllowOffline: false, + } + + for _, opt := range opts { + err := opt(options) + if err != nil { + return nil, err + } + } + + return options, nil +} + +type putOpts struct{} + +var Put putOpts + +// AllowOffline is an option for Routing.Put which specifies whether to allow +// publishing when the node is offline. Default value is false +func (putOpts) AllowOffline(allow bool) RoutingPutOption { + return func(settings *RoutingPutSettings) error { + settings.AllowOffline = allow + return nil + } +} diff --git a/coreiface/routing.go b/coreiface/routing.go index a28ceb9e7..5099c3de0 100644 --- a/coreiface/routing.go +++ b/coreiface/routing.go @@ -2,6 +2,8 @@ package iface import ( "context" + + "github.com/ipfs/boxo/coreiface/options" ) // RoutingAPI specifies the interface to the routing layer. @@ -10,5 +12,5 @@ type RoutingAPI interface { Get(context.Context, string) ([]byte, error) // Put sets a value for a given key - Put(ctx context.Context, key string, value []byte) error + Put(ctx context.Context, key string, value []byte, opts ...options.RoutingPutOption) error } From f2e8db28106c687763d506353f6a134a0a059c57 Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Tue, 2 May 2023 16:31:05 +0200 Subject: [PATCH 2/4] feat(routing): add Put test --- coreiface/tests/api.go | 37 ++++++++++++++++++++++----------- coreiface/tests/routing.go | 42 +++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/coreiface/tests/api.go b/coreiface/tests/api.go index 497ef9d27..cfcf0c976 100644 --- a/coreiface/tests/api.go +++ b/coreiface/tests/api.go @@ -11,21 +11,12 @@ import ( var errAPINotImplemented = errors.New("api not implemented") -func (tp *TestSuite) makeAPI(ctx context.Context) (coreiface.CoreAPI, error) { - api, err := tp.MakeAPISwarm(ctx, false, 1) - if err != nil { - return nil, err - } - - return api[0], nil -} - type Provider interface { // Make creates n nodes. fullIdentity set to false can be ignored - MakeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]coreiface.CoreAPI, error) + MakeAPISwarm(ctx context.Context, fullIdentity bool, online bool, n int) ([]coreiface.CoreAPI, error) } -func (tp *TestSuite) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]coreiface.CoreAPI, error) { +func (tp *TestSuite) makeAPISwarm(ctx context.Context, fullIdentity bool, online bool, n int) ([]coreiface.CoreAPI, error) { if tp.apis != nil { tp.apis <- 1 go func() { @@ -34,7 +25,29 @@ func (tp *TestSuite) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int) }() } - return tp.Provider.MakeAPISwarm(ctx, fullIdentity, n) + return tp.Provider.MakeAPISwarm(ctx, fullIdentity, online, n) +} + +func (tp *TestSuite) makeAPI(ctx context.Context) (coreiface.CoreAPI, error) { + api, err := tp.makeAPISwarm(ctx, false, false, 1) + if err != nil { + return nil, err + } + + return api[0], nil +} + +func (tp *TestSuite) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]coreiface.CoreAPI, error) { + return tp.makeAPISwarm(ctx, fullIdentity, fullIdentity, n) +} + +func (tp *TestSuite) makeAPIWithIdentityAndOffline(ctx context.Context) (coreiface.CoreAPI, error) { + api, err := tp.makeAPISwarm(ctx, true, false, 1) + if err != nil { + return nil, err + } + + return api[0], nil } type TestSuite struct { diff --git a/coreiface/tests/routing.go b/coreiface/tests/routing.go index e1d8d1060..deeccde0b 100644 --- a/coreiface/tests/routing.go +++ b/coreiface/tests/routing.go @@ -7,6 +7,7 @@ import ( "github.com/gogo/protobuf/proto" iface "github.com/ipfs/boxo/coreiface" + "github.com/ipfs/boxo/coreiface/options" ipns_pb "github.com/ipfs/boxo/ipns/pb" ) @@ -20,6 +21,7 @@ func (tp *TestSuite) TestRouting(t *testing.T) { t.Run("TestRoutingGet", tp.TestRoutingGet) t.Run("TestRoutingPut", tp.TestRoutingPut) + t.Run("TestRoutingPutOffline", tp.TestRoutingPutOffline) } func (tp *TestSuite) testRoutingPublishKey(t *testing.T, ctx context.Context, api iface.CoreAPI) iface.IpnsEntry { @@ -28,7 +30,12 @@ func (tp *TestSuite) testRoutingPublishKey(t *testing.T, ctx context.Context, ap t.Fatal(err) } - entry, err := api.Name().Publish(ctx, p) + // TODO: make sure we are fine with that implicit allow offline + opts := []options.NamePublishOption{ + options.Name.AllowOffline(true), + } + + entry, err := api.Name().Publish(ctx, p, opts...) if err != nil { t.Fatal(err) } @@ -90,3 +97,36 @@ func (tp *TestSuite) TestRoutingPut(t *testing.T) { t.Fatal(err) } } + +func (tp *TestSuite) TestRoutingPutOffline(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // init a swarm & publish an IPNS entry to get a valid payload + apis, err := tp.MakeAPISwarm(ctx, 2) + if err != nil { + t.Fatal(err) + } + + ipnsEntry := tp.testRoutingPublishKey(t, ctx, apis[0]) + data, err := apis[0].Routing().Get(ctx, "/ipns/"+ipnsEntry.Name()) + if err != nil { + t.Fatal(err) + } + + // init our offline node and try to put the payload + api, err := tp.makeAPIWithIdentityAndOffline(ctx) + if err != nil { + t.Fatal(err) + } + + err = api.Routing().Put(ctx, "/ipns/"+ipnsEntry.Name(), data) + if err == nil { + t.Fatal("this operation should fail because we are offline") + } + + err = api.Routing().Put(ctx, "/ipns/"+ipnsEntry.Name(), data, options.Put.AllowOffline(true)) + if err != nil { + t.Fatal(err) + } +} From ee04895bb06d3ba271960973370b769ce83351af Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Tue, 2 May 2023 16:46:25 +0200 Subject: [PATCH 3/4] refactor: clearer MakeAPI* --- coreiface/tests/api.go | 8 ++++---- coreiface/tests/dht.go | 6 +++--- coreiface/tests/name.go | 6 +++--- coreiface/tests/pubsub.go | 2 +- coreiface/tests/routing.go | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/coreiface/tests/api.go b/coreiface/tests/api.go index cfcf0c976..f30990512 100644 --- a/coreiface/tests/api.go +++ b/coreiface/tests/api.go @@ -37,10 +37,6 @@ func (tp *TestSuite) makeAPI(ctx context.Context) (coreiface.CoreAPI, error) { return api[0], nil } -func (tp *TestSuite) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]coreiface.CoreAPI, error) { - return tp.makeAPISwarm(ctx, fullIdentity, fullIdentity, n) -} - func (tp *TestSuite) makeAPIWithIdentityAndOffline(ctx context.Context) (coreiface.CoreAPI, error) { api, err := tp.makeAPISwarm(ctx, true, false, 1) if err != nil { @@ -50,6 +46,10 @@ func (tp *TestSuite) makeAPIWithIdentityAndOffline(ctx context.Context) (coreifa return api[0], nil } +func (tp *TestSuite) MakeAPISwarm(ctx context.Context, n int) ([]coreiface.CoreAPI, error) { + return tp.makeAPISwarm(ctx, true, true, n) +} + type TestSuite struct { Provider diff --git a/coreiface/tests/dht.go b/coreiface/tests/dht.go index fb3f6d1a0..61f9fd687 100644 --- a/coreiface/tests/dht.go +++ b/coreiface/tests/dht.go @@ -26,7 +26,7 @@ func (tp *TestSuite) TestDht(t *testing.T) { func (tp *TestSuite) TestDhtFindPeer(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - apis, err := tp.MakeAPISwarm(ctx, true, 5) + apis, err := tp.MakeAPISwarm(ctx, 5) if err != nil { t.Fatal(err) } @@ -81,7 +81,7 @@ func (tp *TestSuite) TestDhtFindPeer(t *testing.T) { func (tp *TestSuite) TestDhtFindProviders(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - apis, err := tp.MakeAPISwarm(ctx, true, 5) + apis, err := tp.MakeAPISwarm(ctx, 5) if err != nil { t.Fatal(err) } @@ -113,7 +113,7 @@ func (tp *TestSuite) TestDhtFindProviders(t *testing.T) { func (tp *TestSuite) TestDhtProvide(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - apis, err := tp.MakeAPISwarm(ctx, true, 5) + apis, err := tp.MakeAPISwarm(ctx, 5) if err != nil { t.Fatal(err) } diff --git a/coreiface/tests/name.go b/coreiface/tests/name.go index a67876cba..a669e0c02 100644 --- a/coreiface/tests/name.go +++ b/coreiface/tests/name.go @@ -43,7 +43,7 @@ func (tp *TestSuite) TestPublishResolve(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() init := func() (coreiface.CoreAPI, path.Path) { - apis, err := tp.MakeAPISwarm(ctx, true, 5) + apis, err := tp.MakeAPISwarm(ctx, 5) if err != nil { t.Fatal(err) return nil, nil @@ -191,7 +191,7 @@ func (tp *TestSuite) TestPublishResolve(t *testing.T) { func (tp *TestSuite) TestBasicPublishResolveKey(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - apis, err := tp.MakeAPISwarm(ctx, true, 5) + apis, err := tp.MakeAPISwarm(ctx, 5) if err != nil { t.Fatal(err) } @@ -235,7 +235,7 @@ func (tp *TestSuite) TestBasicPublishResolveTimeout(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - apis, err := tp.MakeAPISwarm(ctx, true, 5) + apis, err := tp.MakeAPISwarm(ctx, 5) if err != nil { t.Fatal(err) } diff --git a/coreiface/tests/pubsub.go b/coreiface/tests/pubsub.go index 446e0771a..24a8ac309 100644 --- a/coreiface/tests/pubsub.go +++ b/coreiface/tests/pubsub.go @@ -24,7 +24,7 @@ func (tp *TestSuite) TestBasicPubSub(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - apis, err := tp.MakeAPISwarm(ctx, true, 2) + apis, err := tp.MakeAPISwarm(ctx, 2) if err != nil { t.Fatal(err) } diff --git a/coreiface/tests/routing.go b/coreiface/tests/routing.go index deeccde0b..c5486aa72 100644 --- a/coreiface/tests/routing.go +++ b/coreiface/tests/routing.go @@ -48,7 +48,7 @@ func (tp *TestSuite) TestRoutingGet(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - apis, err := tp.MakeAPISwarm(ctx, true, 2) + apis, err := tp.MakeAPISwarm(ctx, 2) if err != nil { t.Fatal(err) } @@ -77,7 +77,7 @@ func (tp *TestSuite) TestRoutingGet(t *testing.T) { func (tp *TestSuite) TestRoutingPut(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - apis, err := tp.MakeAPISwarm(ctx, true, 2) + apis, err := tp.MakeAPISwarm(ctx, 2) if err != nil { t.Fatal(err) } From b81372262c4733e5e8c855674ec5c102843d5b09 Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Wed, 3 May 2023 11:46:59 +0200 Subject: [PATCH 4/4] fix(routing): use explicit opts in test --- coreiface/tests/routing.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/coreiface/tests/routing.go b/coreiface/tests/routing.go index c5486aa72..bf314cafe 100644 --- a/coreiface/tests/routing.go +++ b/coreiface/tests/routing.go @@ -24,17 +24,12 @@ func (tp *TestSuite) TestRouting(t *testing.T) { t.Run("TestRoutingPutOffline", tp.TestRoutingPutOffline) } -func (tp *TestSuite) testRoutingPublishKey(t *testing.T, ctx context.Context, api iface.CoreAPI) iface.IpnsEntry { +func (tp *TestSuite) testRoutingPublishKey(t *testing.T, ctx context.Context, api iface.CoreAPI, opts ...options.NamePublishOption) iface.IpnsEntry { p, err := addTestObject(ctx, api) if err != nil { t.Fatal(err) } - // TODO: make sure we are fine with that implicit allow offline - opts := []options.NamePublishOption{ - options.Name.AllowOffline(true), - } - entry, err := api.Name().Publish(ctx, p, opts...) if err != nil { t.Fatal(err) @@ -108,7 +103,7 @@ func (tp *TestSuite) TestRoutingPutOffline(t *testing.T) { t.Fatal(err) } - ipnsEntry := tp.testRoutingPublishKey(t, ctx, apis[0]) + ipnsEntry := tp.testRoutingPublishKey(t, ctx, apis[0], options.Name.AllowOffline(true)) data, err := apis[0].Routing().Get(ctx, "/ipns/"+ipnsEntry.Name()) if err != nil { t.Fatal(err)