// getOrRequestPublicIdentity retrieves the needed public identity from bmd // or sends a getpubkey request if it doesn't exist in its database. If both // return types are nil, it means a getpubkey request has been queued. func (s *server) getOrRequestPublicIdentity(user uint32, address string) (*identity.Public, error) { serverLog.Debug("getOrRequestPublicIdentity called for ", address) id, err := s.bmd.GetIdentity(address) if err == nil { return id, nil } else if err != rpc.ErrIdentityNotFound { return nil, err } addr, err := bmutil.DecodeAddress(address) if err != nil { return nil, fmt.Errorf("Failed to decode address: %v", err) } serverLog.Debug("getOrRequestPublicIdentity: address not found, send pubkey request.") // We don't have the identity so craft a getpubkey request. var tag wire.ShaHash copy(tag[:], addr.Tag()) msg := obj.NewGetPubKey(0, time.Now().Add(defaultGetpubkeyExpiry), addr.Version, addr.Stream, (*wire.RipeHash)(&addr.Ripe), &tag) // Enqueue the request for proof-of-work. b := wire.EncodeMessage(msg.MsgObject())[8:] // exclude nonce target := pow.CalculateTarget(uint64(len(b)), uint64(msg.Header().Expiration().Sub(time.Now()).Seconds()), pow.DefaultData) s.pow.Run(target, b, func(nonce pow.Nonce) { err := s.Send(append(nonce.Bytes(), b...)) if err != nil { serverLog.Error("Could not run pow: ", err) } // Store a record of the public key request. count, _ := s.pk.New(address) serverLog.Tracef("getOrRequestPublicIdentity: Requested address %s %d time(s).", address, count) }) return nil, nil }
// newGetpubkey is called when a new getpubkey is received by the RPC client. // Getpubkey requests are guaranteed to be received in ascending order of // counter value. func (s *server) newGetpubkey(counter uint64, object []byte) { // Store counter value. atomic.StoreUint64(&s.getpubkeyCounter, counter) msg := &obj.GetPubKey{} err := msg.Decode(bytes.NewReader(object)) if err != nil { serverLog.Errorf("Failed to decode getpubkey #%d from bytes: %v", counter, err) return // Ignore message. } var privID *keymgr.PrivateID header := msg.Header() // Check if the getpubkey request corresponds to any of our identities. for _, user := range s.users { err = user.Keys.ForEach(func(id *keymgr.PrivateID) error { if id.Disabled || id.IsChan { // We don't care about these. return nil } var cond bool // condition to satisfy switch header.Version { case obj.SimplePubKeyVersion, obj.ExtendedPubKeyVersion: cond = bytes.Equal(id.Private.Address.Ripe[:], msg.Ripe[:]) case obj.TagGetPubKeyVersion: cond = bytes.Equal(id.Private.Address.Tag(), msg.Tag[:]) } if cond { privID = id return errors.New("We have a match.") } return nil }) if err != nil { break } } if err == nil { return } addr := privID.Address() serverLog.Infof("Received a getpubkey request for %s, sending out the pubkey.", addr) // Generate a pubkey message. pkMsg, err := cipher.GeneratePubKey(&privID.Private, defaultPubkeyExpiry) if err != nil { serverLog.Errorf("Failed to generate pubkey for %s: %v", addr, err) return } // Add it to pow queue. pkObj := pkMsg.Object().MsgObject() pkHeader := pkObj.Header() b := wire.EncodeMessage(pkObj)[8:] // exclude nonce target := pow.CalculateTarget(uint64(len(b)), uint64(pkHeader.Expiration().Sub(time.Now()).Seconds()), pow.DefaultData) s.pow.Run(target, b, func(nonce pow.Nonce) { s.Send(append(nonce.Bytes(), b...)) }) }