Exemplo n.º 1
0
// 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
}
Exemplo n.º 2
0
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
}
Exemplo n.º 3
0
// 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
}
Exemplo n.º 4
0
// 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
}
Exemplo n.º 5
0
// 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
}
Exemplo n.º 6
0
// 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
}
Exemplo n.º 7
0
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:")
}
Exemplo n.º 8
0
// 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
}
Exemplo n.º 9
0
// 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.
Exemplo n.º 10
0
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 {
Exemplo n.º 11
0
// 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)
	})
}
Exemplo n.º 12
0
// 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
Exemplo n.º 13
0
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 {
Exemplo n.º 14
0
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
}