func (c *Client) Enact(op *SignedProfileOperation, invite []byte) (err error) {
	err = c.atSomeServer(c.update, func(conn *transport.Conn) (bool, error) {
		msg := &ClientMessage{ModifyProfile: op, InviteCode: invite}
		_, err = conn.WriteFrame(Pad(PBEncode(msg), int(pad_to)))
		if err != nil {
			return false, err
		}
		var reply *ClientReply
		reply, err = readReply(conn)
		if err != nil {
			return false, err
		}
		switch reply.GetStatus() {
		case ClientReply_OK:
			return true, nil
		case ClientReply_REGISTRATION_DISABLED:
			return false, ErrRegistrationDisabled
		case ClientReply_INVITE_INVALID:
			return false, ErrInviteInvalid
		case ClientReply_INVITE_USED:
			return false, ErrInviteUsed
		case ClientReply_NOT_AUTHORIZED:
			return false, ErrNotAuthorized
		default:
			return false, fmt.Errorf("unknown status code")
		}
	})
	return
}
Enact is a low-level function that completes an already complete profile
operation at any known server. You probably want to use Register, Modify or
Transfer instead.
package client
import (
	"bytes"
	"golang.org/x/net/proxy"
	"fmt"
	"github.com/agl/ed25519"
	"github.com/andres-erbsen/chatterbox/transport"
	. "github.com/andres-erbsen/dename/protocol"
	"github.com/gogo/protobuf/proto"
	"io"
	"net"
	"time"
)
var true_ = true
var pad_to uint64 = 4 << 10
type verifier struct {
	name string
	pk   *Profile_PublicKey
}
type server struct {
	address     string
	timeout     time.Duration
	transportPK [32]byte
}
type Client struct {
	now                         func() time.Time
	dialer                      proxy.Dialer
	freshnessThreshold          time.Duration
	freshnessSignaturesRequired int
	consensusSignaturesRequired int
	verifier                    map[uint64]*verifier
	update                      []*server
	lookup                      []*server
}
func (c *Client) connect(s *server) (*transport.Conn, error) {
	var plainconn net.Conn
	plainconn, err := c.dialer.Dial("tcp", s.address)
	if err != nil {
		return nil, fmt.Errorf("dial %s: %s", s.address, err)
	}
	plainconn.SetDeadline(time.Now().Add(s.timeout))
	conn, _, err := transport.Handshake(plainconn, nil, nil, &s.transportPK, 1<<12)
	if err != nil {
		plainconn.Close()
		return nil, fmt.Errorf("transport handshake %s: %s", s.address, err)
	}
	return conn, nil
}
func (c *Client) atSomeServer(servers []*server, f func(*transport.Conn) (bool, error)) (err error) {
	for _, server := range servers {
		var conn *transport.Conn
		conn, err = c.connect(server)
		if err != nil {
			continue
		}
		var done bool
		done, err = f(conn)
		conn.Close()
		if done {
			return err
		}
	}
	return err
}
func (c *Client) Lookup(name string) (profile *Profile, err error) {
	profile, _, err = c.LookupReply(name)
	return
}
func (c *Client) LookupReply(name string) (profile *Profile, reply *ClientReply, err error) {
	err = c.atSomeServer(c.lookup, func(conn *transport.Conn) (bool, error) {
		rq := &ClientMessage{PeekState: &true_, ResolveName: []byte(name), PadReplyTo: &pad_to}
		if _, err = conn.WriteFrame(Pad(PBEncode(rq), 256)); err != nil {
			return false, err
		}
		if reply, err = readReply(conn); err != nil {
			return false, err
		}
		if profile, err = c.LookupFromReply(name, reply); err != nil {
			return true, err
		}
		return true, nil
	})
	return
}
func (c *Client) LookupFromReply(name string, reply *ClientReply) (profile *Profile, err error) {
	var root []byte
	root, err = c.VerifyConsensus(reply.StateConfirmations)
	if err != nil {
		return
	}
	profileBs, err := VerifyResolveAgainstRoot(root, name, reply.LookupNodes)
	if err != nil {
		return
	}
	if profileBs == nil {
		profile = nil
		return
	}
	profile = new(Profile)
	err = proto.Unmarshal(profileBs, profile)
	if err != nil {
		return nil, err
	}
	expirationTime := time.Unix(int64(*profile.ExpirationTime), 0)
	if expirationTime.Before(time.Now().Add(MAX_VALIDITY_PERIOD * time.Second / 2)) {
		return profile, errOutOfDate{fmt.Sprintf("the profile is out of date and will be erased completely on %s", expirationTime)}
	}
	return profile, nil
}
var (
	ErrRegistrationDisabled = fmt.Errorf("registration disabled")
	ErrInviteInvalid        = fmt.Errorf("invite not valid")
	ErrInviteUsed           = fmt.Errorf("invite already used")
	ErrNotAuthorized        = fmt.Errorf("not authorized")
	ErrCouldntVerify        = fmt.Errorf("could not verify the correctness of the response")
)
type errOutOfDate struct {
	string
}
func (e errOutOfDate) Error() string {
	return e.string
}
func IsErrOutOfDate(err error) bool {
	switch err.(type) {
	case errOutOfDate:
		return true
	default:
		return false
	}
}