// LookupByAccountID performs a federated lookup following to the stellar // federation protocol using the "id" type request. The provided strkey-encoded // account id is used to resolve what server the request should be made against. func (c *Client) LookupByAccountID(aid string) (*IDResponse, error) { domain, err := c.Horizon.HomeDomainForAccount(aid) if err != nil { return nil, errors.Wrap(err, "get homedomain failed") } if domain == "" { return nil, errors.New("homedomain not set") } fserv, err := c.getFederationServer(domain) if err != nil { return nil, errors.Wrap(err, "lookup federation server failed") } url := c.url(fserv, "id", aid) var resp IDResponse err = c.getJSON(url, &resp) if err != nil { return nil, errors.Wrap(err, "get federation failed") } return &resp, nil }
func (c *Client) getFederationServer(domain string) (string, error) { stoml, err := c.StellarTOML.GetStellarToml(domain) if err != nil { return "", errors.Wrap(err, "get stellar.toml failed") } if stoml.FederationServer == "" { return "", errors.New("stellar.toml is missing federation server info") } if !c.AllowHTTP && !strings.HasPrefix(stoml.FederationServer, "https://") { return "", errors.New("non-https federation server disallowed") } return stoml.FederationServer, nil }
// LookupByAddress performs a federated lookup following to the stellar // federation protocol using the "name" type request. The provided address is // used to resolve what server the request should be made against. NOTE: the // "name" type is a legacy holdover from the legacy stellar network's federation // protocol. It is unfortunate. func (c *Client) LookupByAddress(addy string) (*NameResponse, error) { _, domain, err := address.Split(addy) if err != nil { return nil, errors.Wrap(err, "parse address failed") } fserv, err := c.getFederationServer(domain) if err != nil { return nil, errors.Wrap(err, "lookup federation server failed") } url := c.url(fserv, "name", addy) var resp NameResponse err = c.getJSON(url, &resp) if err != nil { return nil, errors.Wrap(err, "get federation failed") } if resp.MemoType != "" && resp.Memo == "" { return nil, errors.New("Invalid federation response (memo)") } return &resp, nil }
// Rollback rolls back the current transaction func (r *Repo) Rollback() error { if r.tx == nil { return errors.New("not in transaction") } err := r.tx.Rollback() r.logRollback() r.tx = nil return err }
// Commit commits the current transaction func (r *Repo) Commit() error { if r.tx == nil { return errors.New("not in transaction") } err := r.tx.Commit() r.logCommit() r.tx = nil return err }
// Begin binds this repo to a new transaction. func (r *Repo) Begin() error { if r.tx != nil { return errors.New("already in transaction") } tx, err := r.DB.Beginx() if err != nil { return errors.Wrap(err, "beginx failed") } r.logBegin() r.tx = tx return nil }
func TestWithStack(t *testing.T) { output := new(bytes.Buffer) l := New() l.Logger.Formatter.(*logrus.TextFormatter).DisableColors = true l.Logger.Out = output // Adds stack=unknown when the provided err has not stack info l.WithStack(errors.New("broken")).Error("test") assert.Contains(t, output.String(), "stack=unknown") // Adds the stack properly if a go-errors.Error is provided err := serr.New("broken") l.WithStack(err).Error("test") // simply ensure that the line creating the above error is in the log assert.Contains(t, output.String(), "main_test.go:") }
// GetStellarToml returns stellar.toml file for a given domain func (c *Client) GetStellarToml(domain string) (resp *Response, err error) { var hresp *http.Response hresp, err = c.HTTP.Get(c.url(domain)) if err != nil { err = errors.Wrap(err, "http request errored") return } defer hresp.Body.Close() if !(hresp.StatusCode >= 200 && hresp.StatusCode < 300) { err = errors.New("http request failed with non-200 status code") return } _, err = toml.DecodeReader(hresp.Body, &resp) if err != nil { err = errors.Wrap(err, "toml decode failed") return } return }
// Package app provides vars that can be populated via "-X" linker flags to // provide global application metadata, such as build time or version. package app import "time" import "github.com/stellar/go/support/errors" var ( // ErrNoBuildTime is the error returned when no build time for the current // binary was set. ErrNoBuildTime = errors.New("build time not known") ) // BuildTime returns the time that the binary of the current process was built. // Our build script populates the `buildTime` var used to provide this result. func BuildTime() (time.Time, error) { if buildTime == "" { return time.Time{}, ErrNoBuildTime } t, err := time.Parse(time.RFC3339, buildTime) if err != nil { return time.Time{}, errors.Wrap(err, "parse failed") } return t, nil } // Version returns the build version of the binary executing the current // process. Our build script populates the `version` var, if a version tag is // set. If not populated, a generic "devel" value will be returned.
package strkey import ( "bytes" "encoding/base32" "encoding/binary" "github.com/stellar/go/crc16" "github.com/stellar/go/support/errors" ) // ErrInvalidVersionByte is returned when the version byte from a provided // strkey-encoded string is not one of the valid values. var ErrInvalidVersionByte = errors.New("invalid version byte") // VersionByte represents one of the possible prefix values for a StrKey base // string--the string the when encoded using base32 yields a final StrKey. type VersionByte byte const ( //VersionByteAccountID is the version byte used for encoded stellar addresses VersionByteAccountID VersionByte = 6 << 3 // Base32-encodes to 'G...' //VersionByteSeed is the version byte used for encoded stellar seed VersionByteSeed = 18 << 3 // Base32-encodes to 'S...' ) // Decode decodes the provided StrKey into a raw value, checking the checksum // and ensuring the expected VersionByte (the version parameter) is the value // actually encoded into the provided src string. func Decode(expected VersionByte, src string) ([]byte, error) { if err := checkValidVersionByte(expected); err != nil {
// ReturnError causes this expectation to resolve to an error. func (ce *ClientExpectation) ReturnError(msg string) *ClientExpectation { return ce.Return(func(*http.Request) (*http.Response, error) { return nil, errors.New(msg) }) }
// DefaultTestNetClient is a default client to connect to test network var DefaultTestNetClient = &Client{ URL: "https://horizon-testnet.stellar.org", HTTP: http.DefaultClient, } // DefaultPublicNetClient is a default client to connect to public network var DefaultPublicNetClient = &Client{ URL: "https://horizon.stellar.org", HTTP: http.DefaultClient, } var ( // ErrTransactionNotFailed is the error returned from a call to ResultCodes() // against a `Problem` value that is not of type "transaction_failed". ErrTransactionNotFailed = errors.New("cannot get result codes from transaction that did not fail") // ErrResultCodesNotPopulated is the error returned from a call to // ResultCodes() against a `Problem` value that doesn't have the // "result_codes" extra field populated when it is expected to be. ErrResultCodesNotPopulated = errors.New("result_codes not populated") // ErrEnvelopeNotPopulated is the error returned from a call to // Envelope() against a `Problem` value that doesn't have the // "envelope_xdr" extra field populated when it is expected to be. ErrEnvelopeNotPopulated = errors.New("envelope_xdr not populated") ) // Client struct contains data required to connect to Horizon instance type Client struct { // URL of Horizon server to connect
import ( "fmt" "strings" "github.com/asaskevich/govalidator" "github.com/stellar/go/support/errors" ) // Separator seperates the name and domain portions of an address const Separator = "*" var ( // ErrInvalidAddress is the error returned when an address is invalid in // such a way that we do not know if the name or domain portion is at fault. ErrInvalidAddress = errors.New("invalid address") // ErrInvalidName is the error returned when an address's name portion is // invalid. ErrInvalidName = errors.New("name part of address is invalid") // ErrInvalidDomain is the error returned when an address's domain portion // is invalid. ErrInvalidDomain = errors.New("domain part of address is invalid") ) // New returns a new address based upon the provided name and domain. Note: Not // validation is performed on the parts provided... it is possible to create an // invalid address by supplying invalid information, for example, supplying a // blank domain. func New(name, domain string) string {
func (pl *PaymentListener) onPayment(payment horizon.PaymentResponse) (err error) { pl.log.WithFields(logrus.Fields{"id": payment.ID}).Info("New received payment") id, err := strconv.ParseInt(payment.ID, 10, 64) if err != nil { pl.log.WithFields(logrus.Fields{"err": err}).Error("Error converting ID to int64") return err } existingPayment, err := pl.repository.GetReceivedPaymentByID(id) if err != nil { pl.log.WithFields(logrus.Fields{"err": err}).Error("Error checking if receive payment exists") return err } if existingPayment != nil { pl.log.WithFields(logrus.Fields{"id": payment.ID}).Info("Payment already exists") return } dbPayment := entities.ReceivedPayment{ OperationID: payment.ID, ProcessedAt: pl.now(), PagingToken: payment.PagingToken, } savePayment := func(payment *entities.ReceivedPayment) (err error) { err = pl.entityManager.Persist(payment) return } if payment.Type != "payment" && payment.Type != "path_payment" { dbPayment.Status = "Not a payment operation" savePayment(&dbPayment) return } if payment.To != pl.config.Accounts.ReceivingAccountID { dbPayment.Status = "Operation sent not received" savePayment(&dbPayment) return nil } if !pl.isAssetAllowed(payment.AssetCode, payment.AssetIssuer) { dbPayment.Status = "Asset not allowed" savePayment(&dbPayment) return nil } err = pl.horizon.LoadMemo(&payment) if err != nil { pl.log.Error("Unable to load transaction memo") return err } var receiveResponse compliance.ReceiveResponse var route string // Request extra_memo from compliance server if pl.config.Compliance != "" && payment.Memo.Type == "hash" { resp, err := pl.postForm( pl.config.Compliance+"/receive", url.Values{"memo": {string(payment.Memo.Value)}}, ) if err != nil { pl.log.WithFields(logrus.Fields{"err": err}).Error("Error sending request to compliance server") return err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { pl.log.Error("Error reading compliance server response") return err } if resp.StatusCode != 200 { pl.log.WithFields(logrus.Fields{ "status": resp.StatusCode, "body": string(body), }).Error("Error response from compliance server") return err } err = json.Unmarshal([]byte(body), &receiveResponse) if err != nil { pl.log.WithFields(logrus.Fields{"err": err}).Error("Cannot unmarshal receiveResponse") return err } var authData compliance.AuthData err = json.Unmarshal([]byte(receiveResponse.Data), &authData) if err != nil { pl.log.WithFields(logrus.Fields{"err": err}).Error("Cannot unmarshal authData") return err } var memo memo.Memo err = json.Unmarshal([]byte(authData.Memo), &memo) if err != nil { pl.log.WithFields(logrus.Fields{"err": err}).Error("Cannot unmarshal memo") return err } route = memo.Transaction.Route } else if payment.Memo.Type != "hash" { route = payment.Memo.Value } resp, err := pl.postForm( pl.config.Callbacks.Receive, url.Values{ "id": {payment.ID}, "from": {payment.From}, "route": {route}, "amount": {payment.Amount}, "asset_code": {payment.AssetCode}, "memo_type": {payment.Memo.Type}, "memo": {payment.Memo.Value}, "data": {receiveResponse.Data}, }, ) if err != nil { pl.log.Error("Error sending request to receive callback") return err } if resp.StatusCode != 200 { defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { pl.log.Error("Error reading receive callback response") return err } pl.log.WithFields(logrus.Fields{ "status": resp.StatusCode, "body": string(body), }).Error("Error response from receive callback") return errors.New("Error response from receive callback") } dbPayment.Status = "Success" err = savePayment(&dbPayment) if err != nil { pl.log.Error("Error saving payment to the DB") return err } return nil }