diff --git a/core/core.go b/core/core.go index 1e2cf3e30..9a9822fd9 100644 --- a/core/core.go +++ b/core/core.go @@ -370,8 +370,7 @@ func (n *IpfsNode) setupIpnsRepublisher() error { return err } - n.IpnsRepub = ipnsrp.NewRepublisher(n.Routing, n.Repo.Datastore(), n.Peerstore) - n.IpnsRepub.AddName(n.Identity) + n.IpnsRepub = ipnsrp.NewRepublisher(n.Routing, n.Repo.Datastore(), n.PrivateKey, n.Repo.Keystore()) if cfg.Ipns.RepublishPeriod != "" { d, err := time.ParseDuration(cfg.Ipns.RepublishPeriod) diff --git a/namesys/republisher/repub.go b/namesys/republisher/repub.go index 94ad4e8e0..b33328b68 100644 --- a/namesys/republisher/repub.go +++ b/namesys/republisher/repub.go @@ -3,21 +3,21 @@ package republisher import ( "context" "errors" - "sync" "time" + keystore "github.com/ipfs/go-ipfs/keystore" namesys "github.com/ipfs/go-ipfs/namesys" pb "github.com/ipfs/go-ipfs/namesys/pb" path "github.com/ipfs/go-ipfs/path" dshelp "github.com/ipfs/go-ipfs/thirdparty/ds-help" routing "gx/ipfs/QmNdaQ8itUU9jEZUwTsG4gHMaPmRfi6FEe89QjQAFbep3M/go-libp2p-routing" + ic "gx/ipfs/QmP1DfoUjiWH2ZBo1PBH6FupdBucbDepx3HpWmEY6JMUpY/go-libp2p-crypto" ds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore" goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess" gpctx "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess/context" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" recpb "gx/ipfs/QmWYCqr6UDqqD1bfRybaAPtbAqcN3TSJpveaBXMwbQ3ePZ/go-libp2p-record/pb" - pstore "gx/ipfs/QmXZSd1qR5BxZkPyuwfT5jpqQFScZccoZvDneXsKzCNHWX/go-libp2p-peerstore" proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto" peer "gx/ipfs/QmdS9KpbDyPrieswibZhkod1oXqRwZJrUPzxCofAMWpFGq/go-libp2p-peer" ) @@ -31,36 +31,29 @@ var DefaultRebroadcastInterval = time.Hour * 4 const DefaultRecordLifetime = time.Hour * 24 type Republisher struct { - r routing.ValueStore - ds ds.Datastore - ps pstore.Peerstore + r routing.ValueStore + ds ds.Datastore + self ic.PrivKey + ks keystore.Keystore Interval time.Duration // how long records that are republished should be valid for RecordLifetime time.Duration - - entrylock sync.Mutex - entries map[peer.ID]struct{} } -func NewRepublisher(r routing.ValueStore, ds ds.Datastore, ps pstore.Peerstore) *Republisher { +// NewRepublisher creates a new Republisher +func NewRepublisher(r routing.ValueStore, ds ds.Datastore, self ic.PrivKey, ks keystore.Keystore) *Republisher { return &Republisher{ r: r, - ps: ps, ds: ds, - entries: make(map[peer.ID]struct{}), + self: self, + ks: ks, Interval: DefaultRebroadcastInterval, RecordLifetime: DefaultRecordLifetime, } } -func (rp *Republisher) AddName(id peer.ID) { - rp.entrylock.Lock() - defer rp.entrylock.Unlock() - rp.entries[id] = struct{}{} -} - func (rp *Republisher) Run(proc goprocess.Process) { tick := time.NewTicker(rp.Interval) defer tick.Stop() @@ -82,31 +75,61 @@ func (rp *Republisher) republishEntries(p goprocess.Process) error { ctx, cancel := context.WithCancel(gpctx.OnClosingContext(p)) defer cancel() - for id, _ := range rp.entries { - log.Debugf("republishing ipns entry for %s", id) - priv := rp.ps.PrivKey(id) + err := rp.republishEntry(ctx, rp.self) + if err != nil { + return err + } - // Look for it locally only - _, ipnskey := namesys.IpnsKeysForID(id) - p, seq, err := rp.getLastVal(ipnskey) + if rp.ks != nil { + keyNames, err := rp.ks.List() if err != nil { - if err == errNoEntry { - continue + return err + } + for _, name := range keyNames { + priv, err := rp.ks.Get(name) + if err != nil { + return err + } + err = rp.republishEntry(ctx, priv) + if err != nil { + return err } - return err - } - // update record with same sequence number - eol := time.Now().Add(rp.RecordLifetime) - err = namesys.PutRecordToRouting(ctx, priv, p, seq, eol, rp.r, id) - if err != nil { - return err } } return nil } +func (rp *Republisher) republishEntry(ctx context.Context, priv ic.PrivKey) error { + id, err := peer.IDFromPrivateKey(priv) + if err != nil { + return err + } + + log.Debugf("republishing ipns entry for %s", id) + + // Look for it locally only + _, ipnskey := namesys.IpnsKeysForID(id) + p, seq, err := rp.getLastVal(ipnskey) + if err != nil { + if err == errNoEntry { + return nil + } + return err + } + + // update record with same sequence number + eol := time.Now().Add(rp.RecordLifetime) + err = namesys.PutRecordToRouting(ctx, priv, p, seq, eol, rp.r, id) + if err != nil { + println("put record to routing error: " + err.Error()) + return err + } + + return nil +} + func (rp *Republisher) getLastVal(k string) (path.Path, uint64, error) { ival, err := rp.ds.Get(dshelp.NewKeyFromBinary([]byte(k))) if err != nil { diff --git a/namesys/republisher/repub_test.go b/namesys/republisher/repub_test.go index a4810e8ba..d4d7e1282 100644 --- a/namesys/republisher/repub_test.go +++ b/namesys/republisher/repub_test.go @@ -78,10 +78,9 @@ func TestRepublish(t *testing.T) { // The republishers that are contained within the nodes have their timeout set // to 12 hours. Instead of trying to tweak those, we're just going to pretend // they dont exist and make our own. - repub := NewRepublisher(publisher.Routing, publisher.Repo.Datastore(), publisher.Peerstore) + repub := NewRepublisher(publisher.Routing, publisher.Repo.Datastore(), publisher.PrivateKey, publisher.Repo.Keystore()) repub.Interval = time.Second repub.RecordLifetime = time.Second * 5 - repub.AddName(publisher.Identity) proc := goprocess.Go(repub.Run) defer proc.Close() diff --git a/test/sharness/t0240-republisher.sh b/test/sharness/t0240-republisher.sh index 6bb5f60e4..0d0f3661f 100755 --- a/test/sharness/t0240-republisher.sh +++ b/test/sharness/t0240-republisher.sh @@ -94,6 +94,29 @@ go-sleep 15s verify_can_resolve "$num_test_nodes" "$id" "$HASH" "republisher fires after twenty seconds" +# + +test_expect_success "generate new key" ' +KEY2=`ipfsi 1 key gen beepboop --type ed25519` +' + +test_expect_success "publish with new key succeeds" ' + HASH=$(echo "barfoo" | ipfsi 1 add -q) && + ipfsi 1 name publish -t 5s -k "$KEY2" $HASH +' + +verify_can_resolve "$num_test_nodes" "$KEY2" "$HASH" "new key just after publishing" + +go-sleep 5s + +verify_cannot_resolve "$num_test_nodes" "$KEY2" "new key cannot resolve after 5 seconds" + +go-sleep 15s + +verify_can_resolve "$num_test_nodes" "$KEY2" "$HASH" "new key can resolve again after republish" + +# + teardown_iptb test_done