// Lookup will check to see if the Zooko server func (c *Client) lookupString(name string) (string, bool, error) { msg, err := message.CreateMessage(&message.LookupName{ Lookup: &name, }, c.Origin, config.ServerAddress()) if err != nil { return "", false, err } data, typ, h, err := adMessage.SendMessageAndReceiveWithTimestamp( msg, c.Origin, config.ServerAddress()) if err != nil { return "", false, err } else if typ == wire.ErrorCode { return "", false, adErrors.CreateErrorFromBytes(data, h) } if typ != message.TypeResolvedName { return "", false, errors.New("zooko/resolver: received incorrect message reply") } parsed := new(message.ResolvedName) err = proto.Unmarshal(data, parsed) if err != nil { return "", false, err } return string(parsed.Value), *parsed.Found, nil }
func (c *Client) LookupPrefix(prefix string) ([]string, error) { trueVal := true msg, err := message.CreateMessage(&message.LookupName{ Lookup: &prefix, Prefix: &trueVal, }, c.Origin, config.ServerAddress()) if err != nil { return nil, err } data, typ, h, err := adMessage.SendMessageAndReceiveWithTimestamp( msg, c.Origin, config.ServerAddress()) if err != nil { return nil, err } else if typ == wire.ErrorCode { return nil, adErrors.CreateErrorFromBytes(data, h) } if typ != message.TypeListNames { return nil, errors.New("zooko/resolver: received incorrect message reply") } parsed := new(message.ListName) err = proto.Unmarshal(data, parsed) if err != nil { return nil, err } return parsed.Name, nil }
func (c *Client) checkAccountBalance(acc *account.Account, registration bool) error { minimum := int64(account.NameMinimumBalance) if registration { // If we are doing the first registration of a name, // we must have enough coins for two of the // transactions. minimum *= 2 } if acc.Balance() < minimum { // We must endow the account with funds. // Grab the namecoin address of the account hash, err := acc.PublicKeyHash() if err != nil { return err } addr := hash.String() endowRequest, err := message.CreateMessage(&message.RequestFunds{ Address: &addr, }, c.Origin, config.ServerAddress()) if err != nil { return err } data, typ, h, err := adMessage.SendMessageAndReceiveWithTimestamp( endowRequest, c.Origin, config.ServerAddress()) if err != nil { return err } else if typ == wire.ErrorCode { return adErrors.CreateErrorFromBytes(data, h) } else if typ != message.TypeTransferFunds { return errors.New("zooko/resolver: endowment received incorrect response type") } transferredFunds := new(message.TransferFunds) if err := proto.Unmarshal(data, transferredFunds); err != nil { return err } // Build the UTXO for the account acc.Unspent = append(acc.Unspent, &account.UTXO{ TxID: *transferredFunds.Id, Output: *transferredFunds.Index, PkScript: transferredFunds.Script, Amount: *transferredFunds.Amount, }) // Go ahead and ensure that the account is now over the minimum return c.checkAccountBalance(acc, registration) } // Otherwise, we are good to go. return nil }
func (c *Client) getRegistrationResponse(msg adMessage.Message) error { data, typ, h, err := adMessage.SendMessageAndReceiveWithTimestamp(msg, c.Origin, config.ServerAddress()) if err != nil { return err } else if typ == wire.ErrorCode { return adErrors.CreateErrorFromBytes(data, h) } else if typ != message.TypeRegistrationResponse { return errors.New("zooko: received message with incorrect type") } response := new(message.RegistrationResponse) if err := proto.Unmarshal(data, response); err != nil { return err } if !*response.Success { return fmt.Errorf("zooko/resolver: got error registering: %s", *response.Information) } return nil }
// Renew will handle renewing (or updating) a name that is already // owned by acc on the Zooko server. func (c *Client) Renew(name string, reg *Registration, acc *account.Account) error { jsonRegistration, err := json.Marshal(reg) if err != nil { return err } if err := c.checkAccountBalance(acc, false); err != nil { return err } nameUpdate, err := acc.CreateNameUpdate(name, string(jsonRegistration)) if err != nil { return err } nameUpdateBytes := &bytes.Buffer{} if err := nameUpdate.Serialize(nameUpdateBytes); err != nil { return err } updateMsg, err := message.CreateMessage(&message.RenewName{ Name: &name, Value: jsonRegistration, NameUpdate: nameUpdateBytes.Bytes(), }, c.Origin, config.ServerAddress()) if err != nil { return err } if err := c.getRegistrationResponse(updateMsg); err != nil { return err } // Commit to the transaction since the server accepted it. acc.Commit(nameUpdate) return nil }
// Register will handle the registration of a new name in the Zooko server. func (c *Client) Register(name string, reg interface{}, acc *account.Account) error { if _, found, _ := c.lookupString(name); found { return errors.New("zooko: cannot register name that already exists") } jsonRegistration, err := json.Marshal(reg) if err != nil { return err } if err := c.checkAccountBalance(acc, true); err != nil { return err } nameNew, rand, err := acc.CreateNameNew(name) if err != nil { return err } // Temporarily commit to the new transaction so that we can // successfully create the name_firstupdate transaction. oldUnspent := acc.Unspent acc.Commit(nameNew) undoCommit := func() { acc.Unspent = oldUnspent } nameUpdate, err := acc.CreateNameFirstUpdate(rand, name, string(jsonRegistration)) if err != nil { undoCommit() return err } nameNewBytes := &bytes.Buffer{} if err := nameNew.MsgTx.Serialize(nameNewBytes); err != nil { undoCommit() return err } nameFirstUpdateBytes := &bytes.Buffer{} if err := nameUpdate.MsgTx.Serialize(nameFirstUpdateBytes); err != nil { undoCommit() return err } registrationMsg, err := message.CreateMessage(&message.RegisterName{ Name: &name, Value: jsonRegistration, NameNew: nameNewBytes.Bytes(), NameFirstupdate: nameFirstUpdateBytes.Bytes(), }, c.Origin, config.ServerAddress()) if err != nil { undoCommit() return err } if err := c.getRegistrationResponse(registrationMsg); err != nil { undoCommit() return err } // Add the name_firstupdate transaction to the list of pending // transactions. acc.Pending = append(acc.Pending, nameUpdate) return nil }