From 0358cef58b9e3dd3793a2fcc91b0a0f8980b7058 Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Fri, 18 Oct 2019 17:19:28 +0200 Subject: [PATCH 1/6] services/horizon: Use new ingestion data in `/accounts/{account_id}` --- services/horizon/internal/action.go | 7 +- services/horizon/internal/actions/account.go | 197 +++++++++++++++++- .../horizon/internal/actions/account_test.go | 7 +- .../internal/db2/history/account_data.go | 8 + .../db2/history/account_data_value.go | 4 + .../internal/db2/history/account_signers.go | 11 + .../horizon/internal/db2/history/accounts.go | 7 + .../internal/db2/history/trust_lines.go | 7 + .../internal/resourceadapter/account_entry.go | 3 +- .../internal/resourceadapter/signer.go | 2 +- xdr/account_entry.go | 8 +- xdr/account_thresholds.go | 17 ++ 12 files changed, 267 insertions(+), 11 deletions(-) create mode 100644 xdr/account_thresholds.go diff --git a/services/horizon/internal/action.go b/services/horizon/internal/action.go index 3eea4b6ad1..396102f1f2 100644 --- a/services/horizon/internal/action.go +++ b/services/horizon/internal/action.go @@ -175,7 +175,12 @@ type showActionQueryParams struct { // getAccountInfo returns the information about an account based on the provided param. func (w *web) getAccountInfo(ctx context.Context, qp *showActionQueryParams) (interface{}, error) { - return actions.AccountInfo(ctx, &core.Q{w.coreSession(ctx)}, qp.AccountID) + horizonSession, err := w.horizonSession(ctx) + if err != nil { + return nil, errors.Wrap(err, "getting horizon db session") + } + + return actions.AccountInfo(ctx, &core.Q{w.coreSession(ctx)}, &history.Q{horizonSession}, qp.AccountID) } // getTransactionPage returns a page containing the transaction records of an account or a ledger. diff --git a/services/horizon/internal/actions/account.go b/services/horizon/internal/actions/account.go index cc1b9fced1..4ccc45d1cd 100644 --- a/services/horizon/internal/actions/account.go +++ b/services/horizon/internal/actions/account.go @@ -2,6 +2,8 @@ package actions import ( "context" + "encoding/json" + "fmt" "net/http" protocol "github.com/stellar/go/protocols/horizon" @@ -9,11 +11,12 @@ import ( "github.com/stellar/go/services/horizon/internal/db2/history" "github.com/stellar/go/services/horizon/internal/resourceadapter" "github.com/stellar/go/support/errors" + "github.com/stellar/go/support/log" "github.com/stellar/go/support/render/hal" ) // AccountInfo returns the information about an account identified by addr. -func AccountInfo(ctx context.Context, cq *core.Q, addr string) (*protocol.Account, error) { +func AccountInfo(ctx context.Context, cq *core.Q, hq *history.Q, addr string) (*protocol.Account, error) { var ( coreRecord core.Account coreData []core.AccountData @@ -50,8 +53,198 @@ func AccountInfo(ctx context.Context, cq *core.Q, addr string) (*protocol.Accoun coreSigners, coreTrustlines, ) + if err != nil { + return nil, errors.Wrap(err, "populating account") + } + + c, err := json.Marshal(resource) + if err != nil { + return nil, errors.Wrap(err, "error marshaling resource") + } + + // We send JSON bytes to compareAccountResults to prevent modifying + // `resource` by any way. + err = compareAccountResults(ctx, hq, c, addr) + if err != nil { + log.Ctx(ctx).WithFields(log.F{ + "err": err, + "accounts_check": true, // So it's easy to find all diffs + }).Warn("error comparing core and horizon accounts") + } + + return &resource, nil +} + +func compareAccountResults( + ctx context.Context, + hq *history.Q, + expectedResourceBytes []byte, + addr string, +) error { + var ( + horizonRecord history.AccountEntry + horizonData []history.Data + horizonSigners []history.AccountSigner + horizonTrustLines []history.TrustLine + newResource protocol.Account + ) + + horizonRecord, err := hq.GetAccountByID(addr) + if err != nil { + return err + } + + horizonData, err = hq.GetAccountDataByAccountID(addr) + if err != nil { + return err + } + + horizonSigners, err = hq.GetAccountSignersByAccountID(addr) + if err != nil { + return err + } + + horizonTrustLines, err = hq.GetTrustLinesByAccountID(addr) + if err != nil { + return err + } + + err = resourceadapter.PopulateAccountEntry( + ctx, + &newResource, + horizonRecord, + horizonData, + horizonSigners, + horizonTrustLines, + ) + if err != nil { + return err + } + + var expectedResource protocol.Account + err = json.Unmarshal(expectedResourceBytes, &expectedResource) + if err != nil { + return errors.Wrap(err, "Error unmarshaling expectedResourceBytes") + } + + if err = accountResourcesEqual(newResource, expectedResource); err != nil { + return errors.Wrap( + err, + fmt.Sprintf( + "Core and Horizon accounts responses do not match: %+v %+v", + expectedResource, newResource, + )) + + } + + return nil +} + +// accountResourcesEqual compares two protocol.Account objects and returns an +// error if they are different but only if `LastModifiedLedger` fields are the +// same. +func accountResourcesEqual(actual, expected protocol.Account) error { + if actual.Links != expected.Links { + return errors.New("Links are different") + } + + if actual.LastModifiedLedger != expected.LastModifiedLedger { + // Modified at different ledgers so values will be different + return nil + } + + if actual.ID != expected.ID || + actual.AccountID != expected.AccountID || + actual.Sequence != expected.Sequence || + actual.SubentryCount != expected.SubentryCount || + actual.InflationDestination != expected.InflationDestination || + actual.HomeDomain != expected.HomeDomain || + actual.Thresholds != expected.Thresholds || + actual.Flags != expected.Flags { + return errors.New("Main fields are different") + } + + // Ignore PT + + // Balances + balances := map[string]protocol.Balance{} + for _, balance := range expected.Balances { + id := balance.Asset.Type + balance.Asset.Code + balance.Asset.Issuer + balances[id] = balance + } + + for _, actualBalance := range actual.Balances { + id := actualBalance.Asset.Type + actualBalance.Asset.Code + actualBalance.Asset.Issuer + expectedBalance := balances[id] + delete(balances, id) + + if expectedBalance.LastModifiedLedger != actualBalance.LastModifiedLedger { + // Modified at different ledgers so values will be different + continue + } + + if expectedBalance.Balance != actualBalance.Balance || + expectedBalance.Limit != actualBalance.Limit || + expectedBalance.BuyingLiabilities != actualBalance.BuyingLiabilities || + expectedBalance.SellingLiabilities != actualBalance.SellingLiabilities { + return errors.New("Balance " + id + " is different") + } + + if expectedBalance.IsAuthorized == nil && actualBalance.IsAuthorized == nil { + continue + } + + if expectedBalance.IsAuthorized != nil && actualBalance.IsAuthorized != nil && + *expectedBalance.IsAuthorized == *actualBalance.IsAuthorized { + continue + } + + return errors.New("IsAuthorized is different for " + id) + } + + if len(balances) > 0 { + return errors.New("Some extra balances") + } + + // Signers + signers := map[string]protocol.Signer{} + for _, signer := range expected.Signers { + signers[signer.Key] = signer + } + + for _, actualSigner := range actual.Signers { + expectedSigner := signers[actualSigner.Key] + delete(signers, actualSigner.Key) + + if expectedSigner != actualSigner { + return errors.New("Signer is different") + } + } + + if len(signers) > 0 { + return errors.New("Extra signers") + } + + // Data + data := map[string]string{} + for key, value := range expected.Data { + data[key] = value + } + + for actualKey, actualValue := range actual.Data { + expectedValue := data[actualKey] + delete(data, actualKey) + + if expectedValue != actualValue { + return errors.New("Data is different") + } + } + + if len(data) > 0 { + return errors.New("Extra data") + } - return &resource, errors.Wrap(err, "populating account") + return nil } // GetAccountsHandler is the action handler for the /accounts endpoint diff --git a/services/horizon/internal/actions/account_test.go b/services/horizon/internal/actions/account_test.go index fec44fc2d2..5d2cd23b26 100644 --- a/services/horizon/internal/actions/account_test.go +++ b/services/horizon/internal/actions/account_test.go @@ -14,7 +14,12 @@ func TestAccountInfo(t *testing.T) { tt := test.Start(t).Scenario("allow_trust") defer tt.Finish() - account, err := AccountInfo(tt.Ctx, &core.Q{tt.CoreSession()}, "GCXKG6RN4ONIEPCMNFB732A436Z5PNDSRLGWK7GBLCMQLIFO4S7EYWVU") + account, err := AccountInfo( + tt.Ctx, + &core.Q{tt.CoreSession()}, + &history.Q{tt.HorizonSession()}, + "GCXKG6RN4ONIEPCMNFB732A436Z5PNDSRLGWK7GBLCMQLIFO4S7EYWVU", + ) tt.Assert.NoError(err) tt.Assert.Equal("8589934593", account.Sequence) diff --git a/services/horizon/internal/db2/history/account_data.go b/services/horizon/internal/db2/history/account_data.go index 5805c3b8e1..25d600ec6e 100644 --- a/services/horizon/internal/db2/history/account_data.go +++ b/services/horizon/internal/db2/history/account_data.go @@ -19,6 +19,14 @@ func (q *Q) CountAccountsData() (int, error) { return count, nil } +// GetAccountDataByAccountID loads account data for a given account ID +func (q *Q) GetAccountDataByAccountID(id string) ([]Data, error) { + var data []Data + sql := selectAccountData.Where(sq.Eq{"account": id}) + err := q.Select(&data, sql) + return data, err +} + // GetAccountDataByKeys loads a row from the `accounts_data` table, selected by multiple keys. func (q *Q) GetAccountDataByKeys(keys []xdr.LedgerKeyData) ([]Data, error) { var data []Data diff --git a/services/horizon/internal/db2/history/account_data_value.go b/services/horizon/internal/db2/history/account_data_value.go index 25b2c55b23..efcd8d319b 100644 --- a/services/horizon/internal/db2/history/account_data_value.go +++ b/services/horizon/internal/db2/history/account_data_value.go @@ -24,3 +24,7 @@ func (t *AccountDataValue) Scan(src interface{}) error { func (value AccountDataValue) Value() (driver.Value, error) { return driver.Value([]uint8(base64.StdEncoding.EncodeToString(value))), nil } + +func (value AccountDataValue) Base64() string { + return base64.StdEncoding.EncodeToString(value) +} diff --git a/services/horizon/internal/db2/history/account_signers.go b/services/horizon/internal/db2/history/account_signers.go index d99865c6ea..b6d5f9b84e 100644 --- a/services/horizon/internal/db2/history/account_signers.go +++ b/services/horizon/internal/db2/history/account_signers.go @@ -6,6 +6,17 @@ import ( "github.com/stellar/go/support/errors" ) +func (q *Q) GetAccountSignersByAccountID(id string) ([]AccountSigner, error) { + sql := selectAccountSigners.Where(sq.Eq{"accounts_signers.account": id}) + + var results []AccountSigner + if err := q.Select(&results, sql); err != nil { + return nil, errors.Wrap(err, "could not run select query") + } + + return results, nil +} + func (q *Q) SignersForAccounts(accounts []string) ([]AccountSigner, error) { sql := selectAccountSigners.Where(map[string]interface{}{"accounts_signers.account": accounts}) diff --git a/services/horizon/internal/db2/history/accounts.go b/services/horizon/internal/db2/history/accounts.go index 85ed57cd23..b36a59d38d 100644 --- a/services/horizon/internal/db2/history/accounts.go +++ b/services/horizon/internal/db2/history/accounts.go @@ -36,6 +36,13 @@ func (q *Q) CountAccounts() (int, error) { return count, nil } +func (q *Q) GetAccountByID(id string) (AccountEntry, error) { + var account AccountEntry + sql := selectAccounts.Where(sq.Eq{"account_id": id}) + err := q.Get(&account, sql) + return account, err +} + func (q *Q) GetAccountsByIDs(ids []string) ([]AccountEntry, error) { var accounts []AccountEntry sql := selectAccounts.Where(map[string]interface{}{"accounts.account_id": ids}) diff --git a/services/horizon/internal/db2/history/trust_lines.go b/services/horizon/internal/db2/history/trust_lines.go index 593c908947..825427566e 100644 --- a/services/horizon/internal/db2/history/trust_lines.go +++ b/services/horizon/internal/db2/history/trust_lines.go @@ -25,6 +25,13 @@ func (q *Q) CountTrustLines() (int, error) { return count, nil } +func (q *Q) GetTrustLinesByAccountID(id string) ([]TrustLine, error) { + var trustLines []TrustLine + sql := selectTrustLines.Where(sq.Eq{"accountid": id}) + err := q.Select(&trustLines, sql) + return trustLines, err +} + // GetTrustLinesByKeys loads a row from the `trust_lines` table, selected by multiple keys. func (q *Q) GetTrustLinesByKeys(keys []xdr.LedgerKeyTrustLine) ([]TrustLine, error) { var trustLines []TrustLine diff --git a/services/horizon/internal/resourceadapter/account_entry.go b/services/horizon/internal/resourceadapter/account_entry.go index f8f551ad27..7e9e8bfba0 100644 --- a/services/horizon/internal/resourceadapter/account_entry.go +++ b/services/horizon/internal/resourceadapter/account_entry.go @@ -2,7 +2,6 @@ package resourceadapter import ( "context" - "encoding/base64" "fmt" "strconv" @@ -63,7 +62,7 @@ func PopulateAccountEntry( // populate data dest.Data = make(map[string]string) for _, d := range accountData { - dest.Data[d.Name] = base64.StdEncoding.EncodeToString(d.Value) + dest.Data[d.Name] = d.Value.Base64() } masterKeyIncluded := false diff --git a/services/horizon/internal/resourceadapter/signer.go b/services/horizon/internal/resourceadapter/signer.go index ae2e931569..2dd74ac41f 100644 --- a/services/horizon/internal/resourceadapter/signer.go +++ b/services/horizon/internal/resourceadapter/signer.go @@ -15,7 +15,7 @@ func PopulateSigner(ctx context.Context, dest *protocol.Signer, row core.Signer) dest.Type = protocol.MustKeyTypeFromAddress(dest.Key) } -// PopulateMaster fills out the fields of the signer, using a stellar account to +// PopulateMasterSigner fills out the fields of the signer, using a stellar account to // provide the data. func PopulateMasterSigner(dest *protocol.Signer, row core.Account) { dest.Weight = int32(row.Thresholds[0]) diff --git a/xdr/account_entry.go b/xdr/account_entry.go index b852e97f6d..6e6f208bbd 100644 --- a/xdr/account_entry.go +++ b/xdr/account_entry.go @@ -14,17 +14,17 @@ func (a *AccountEntry) SignerSummary() map[string]int32 { } func (a *AccountEntry) MasterKeyWeight() byte { - return a.Thresholds[0] + return a.Thresholds.MasterKeyWeight() } func (a *AccountEntry) ThresholdLow() byte { - return a.Thresholds[1] + return a.Thresholds.ThresholdLow() } func (a *AccountEntry) ThresholdMedium() byte { - return a.Thresholds[2] + return a.Thresholds.ThresholdMedium() } func (a *AccountEntry) ThresholdHigh() byte { - return a.Thresholds[3] + return a.Thresholds.ThresholdHigh() } diff --git a/xdr/account_thresholds.go b/xdr/account_thresholds.go new file mode 100644 index 0000000000..a9a6bf6d09 --- /dev/null +++ b/xdr/account_thresholds.go @@ -0,0 +1,17 @@ +package xdr + +func (t Thresholds) MasterKeyWeight() byte { + return t[0] +} + +func (t Thresholds) ThresholdLow() byte { + return t[1] +} + +func (t Thresholds) ThresholdMedium() byte { + return t[2] +} + +func (t Thresholds) ThresholdHigh() byte { + return t[3] +} From 62a083e489744c611e789a910f87f4416ba54d26 Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Tue, 22 Oct 2019 18:09:43 +0200 Subject: [PATCH 2/6] Start transaction --- services/horizon/internal/action.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/services/horizon/internal/action.go b/services/horizon/internal/action.go index 396102f1f2..2547f65c16 100644 --- a/services/horizon/internal/action.go +++ b/services/horizon/internal/action.go @@ -2,6 +2,7 @@ package horizon import ( "context" + "database/sql" "net/http" "net/url" "strings" @@ -180,6 +181,16 @@ func (w *web) getAccountInfo(ctx context.Context, qp *showActionQueryParams) (in return nil, errors.Wrap(err, "getting horizon db session") } + err = horizonSession.BeginTx(&sql.TxOptions{ + Isolation: sql.LevelRepeatableRead, + ReadOnly: true, + }) + if err != nil { + return nil, errors.Wrap(err, "rrror starting transaction") + } + + defer horizonSession.Rollback() + return actions.AccountInfo(ctx, &core.Q{w.coreSession(ctx)}, &history.Q{horizonSession}, qp.AccountID) } From 30dd4b5bf6125b0010343d9262fad57f82433d31 Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Mon, 28 Oct 2019 17:38:40 +0100 Subject: [PATCH 3/6] Check expingest value --- services/horizon/internal/action.go | 34 ++++++++++++-------- services/horizon/internal/action_test.go | 9 ++++-- services/horizon/internal/actions/account.go | 28 ++++++++-------- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/services/horizon/internal/action.go b/services/horizon/internal/action.go index 2547f65c16..1644118845 100644 --- a/services/horizon/internal/action.go +++ b/services/horizon/internal/action.go @@ -176,22 +176,30 @@ type showActionQueryParams struct { // getAccountInfo returns the information about an account based on the provided param. func (w *web) getAccountInfo(ctx context.Context, qp *showActionQueryParams) (interface{}, error) { - horizonSession, err := w.horizonSession(ctx) - if err != nil { - return nil, errors.Wrap(err, "getting horizon db session") - } + // Use AppFromContext to prevent larger refactoring of actions code. Will + // be removed once this endpoint is migrated to use new actions design. + app := AppFromContext(ctx) + var historyQ *history.Q + + if app.config.EnableExperimentalIngestion { + horizonSession, err := w.horizonSession(ctx) + if err != nil { + return nil, errors.Wrap(err, "getting horizon db session") + } - err = horizonSession.BeginTx(&sql.TxOptions{ - Isolation: sql.LevelRepeatableRead, - ReadOnly: true, - }) - if err != nil { - return nil, errors.Wrap(err, "rrror starting transaction") - } + err = horizonSession.BeginTx(&sql.TxOptions{ + Isolation: sql.LevelRepeatableRead, + ReadOnly: true, + }) + if err != nil { + return nil, errors.Wrap(err, "error starting transaction") + } - defer horizonSession.Rollback() + defer horizonSession.Rollback() + historyQ = &history.Q{horizonSession} + } - return actions.AccountInfo(ctx, &core.Q{w.coreSession(ctx)}, &history.Q{horizonSession}, qp.AccountID) + return actions.AccountInfo(ctx, &core.Q{w.coreSession(ctx)}, historyQ, qp.AccountID, app.config.EnableExperimentalIngestion) } // getTransactionPage returns a page containing the transaction records of an account or a ledger. diff --git a/services/horizon/internal/action_test.go b/services/horizon/internal/action_test.go index e7e4f9df78..3349a89272 100644 --- a/services/horizon/internal/action_test.go +++ b/services/horizon/internal/action_test.go @@ -27,7 +27,12 @@ func TestGetAccountInfo(t *testing.T) { w := mustInitWeb(context.Background(), &history.Q{tt.HorizonSession()}, &core.Q{tt.CoreSession()}, time.Duration(5), 0, true) - res, err := w.getAccountInfo(tt.Ctx, &showActionQueryParams{AccountID: "GCXKG6RN4ONIEPCMNFB732A436Z5PNDSRLGWK7GBLCMQLIFO4S7EYWVU"}) + ctx := withAppContext(tt.Ctx, &App{ + config: Config{ + EnableExperimentalIngestion: false, + }, + }) + res, err := w.getAccountInfo(ctx, &showActionQueryParams{AccountID: "GCXKG6RN4ONIEPCMNFB732A436Z5PNDSRLGWK7GBLCMQLIFO4S7EYWVU"}) tt.Assert.NoError(err) account, ok := res.(*horizon.Account) @@ -46,7 +51,7 @@ func TestGetAccountInfo(t *testing.T) { } } - _, err = w.getAccountInfo(tt.Ctx, &showActionQueryParams{AccountID: "GDBAPLDCAEJV6LSEDFEAUDAVFYSNFRUYZ4X75YYJJMMX5KFVUOHX46SQ"}) + _, err = w.getAccountInfo(ctx, &showActionQueryParams{AccountID: "GDBAPLDCAEJV6LSEDFEAUDAVFYSNFRUYZ4X75YYJJMMX5KFVUOHX46SQ"}) tt.Assert.Equal(errors.Cause(err), sql.ErrNoRows) } diff --git a/services/horizon/internal/actions/account.go b/services/horizon/internal/actions/account.go index 4ccc45d1cd..be6ea965fd 100644 --- a/services/horizon/internal/actions/account.go +++ b/services/horizon/internal/actions/account.go @@ -16,7 +16,7 @@ import ( ) // AccountInfo returns the information about an account identified by addr. -func AccountInfo(ctx context.Context, cq *core.Q, hq *history.Q, addr string) (*protocol.Account, error) { +func AccountInfo(ctx context.Context, cq *core.Q, hq *history.Q, addr string, enableExperimentalIngestion bool) (*protocol.Account, error) { var ( coreRecord core.Account coreData []core.AccountData @@ -57,19 +57,21 @@ func AccountInfo(ctx context.Context, cq *core.Q, hq *history.Q, addr string) (* return nil, errors.Wrap(err, "populating account") } - c, err := json.Marshal(resource) - if err != nil { - return nil, errors.Wrap(err, "error marshaling resource") - } + if enableExperimentalIngestion { + c, err := json.Marshal(resource) + if err != nil { + return nil, errors.Wrap(err, "error marshaling resource") + } - // We send JSON bytes to compareAccountResults to prevent modifying - // `resource` by any way. - err = compareAccountResults(ctx, hq, c, addr) - if err != nil { - log.Ctx(ctx).WithFields(log.F{ - "err": err, - "accounts_check": true, // So it's easy to find all diffs - }).Warn("error comparing core and horizon accounts") + // We send JSON bytes to compareAccountResults to prevent modifying + // `resource` in any way. + err = compareAccountResults(ctx, hq, c, addr) + if err != nil { + log.Ctx(ctx).WithFields(log.F{ + "err": err, + "accounts_check": true, // So it's easy to find all diffs + }).Warn("error comparing core and horizon accounts") + } } return &resource, nil From 9c4a84bc4a6b2e02f5682c4557423e17da381dcf Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Mon, 28 Oct 2019 17:43:10 +0100 Subject: [PATCH 4/6] Fix tests --- services/horizon/internal/actions/account_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/services/horizon/internal/actions/account_test.go b/services/horizon/internal/actions/account_test.go index 5d2cd23b26..b9a49fd18d 100644 --- a/services/horizon/internal/actions/account_test.go +++ b/services/horizon/internal/actions/account_test.go @@ -19,6 +19,7 @@ func TestAccountInfo(t *testing.T) { &core.Q{tt.CoreSession()}, &history.Q{tt.HorizonSession()}, "GCXKG6RN4ONIEPCMNFB732A436Z5PNDSRLGWK7GBLCMQLIFO4S7EYWVU", + false, ) tt.Assert.NoError(err) From 88bef55e49563a15138108c637d9dbf2fdf24eb1 Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Wed, 30 Oct 2019 15:46:55 +0100 Subject: [PATCH 5/6] Tests --- .../internal/db2/history/account_data_test.go | 22 ++++++++++++ .../db2/history/account_signers_test.go | 34 +++++++++++++++++++ .../internal/db2/history/accounts_test.go | 28 +++++++++++++++ .../internal/db2/history/trust_lines_test.go | 23 +++++++++++++ 4 files changed, 107 insertions(+) diff --git a/services/horizon/internal/db2/history/account_data_test.go b/services/horizon/internal/db2/history/account_data_test.go index b94aaba036..41861cb2c2 100644 --- a/services/horizon/internal/db2/history/account_data_test.go +++ b/services/horizon/internal/db2/history/account_data_test.go @@ -132,3 +132,25 @@ func TestGetAccountDataByAccountsID(t *testing.T) { assert.Equal(t, data2.DataName, xdr.String64(datas[1].Name)) assert.Equal(t, []byte(data2.DataValue), []byte(datas[1].Value)) } + +func TestGetAccountDataByAccountID(t *testing.T) { + tt := test.Start(t) + defer tt.Finish() + test.ResetHorizonDB(t, tt.HorizonDB) + q := &Q{tt.HorizonSession()} + + _, err := q.InsertAccountData(data1, 1234) + assert.NoError(t, err) + _, err = q.InsertAccountData(data2, 1235) + assert.NoError(t, err) + + datas, err := q.GetAccountDataByAccountID(data1.AccountId.Address()) + assert.NoError(t, err) + assert.Len(t, datas, 2) + + assert.Equal(t, data1.DataName, xdr.String64(datas[0].Name)) + assert.Equal(t, []byte(data1.DataValue), []byte(datas[0].Value)) + + assert.Equal(t, data2.DataName, xdr.String64(datas[1].Name)) + assert.Equal(t, []byte(data2.DataValue), []byte(datas[1].Value)) +} diff --git a/services/horizon/internal/db2/history/account_signers_test.go b/services/horizon/internal/db2/history/account_signers_test.go index 7b68c631bb..cc3f116105 100644 --- a/services/horizon/internal/db2/history/account_signers_test.go +++ b/services/horizon/internal/db2/history/account_signers_test.go @@ -123,3 +123,37 @@ func TestRemoveAccountSigner(t *testing.T) { tt.Assert.NoError(err) tt.Assert.Len(results, 0) } + +func TestGetAccountSignersByAccountID(t *testing.T) { + tt := test.Start(t).Scenario("base") + defer tt.Finish() + q := &Q{tt.HorizonSession()} + + account := "GA5WBPYA5Y4WAEHXWR2UKO2UO4BUGHUQ74EUPKON2QHV4WRHOIRNKKH6" + signer := "GC2WJF6YWMAEHGGAK2UOMZCIOMH4RU7KY2CQEWZQJV2ZQJVXJ335ZSXG" + weight := int32(123) + _, err := q.CreateAccountSigner(account, signer, weight) + tt.Assert.NoError(err) + + signer2 := "GC23QF2HUE52AMXUFUH3AYJAXXGXXV2VHXYYR6EYXETPKDXZSAW67XO7" + weight2 := int32(100) + _, err = q.CreateAccountSigner(account, signer2, weight2) + tt.Assert.NoError(err) + + expected := []AccountSigner{ + AccountSigner{ + Account: account, + Signer: signer2, + Weight: weight2, + }, + AccountSigner{ + Account: account, + Signer: signer, + Weight: weight, + }, + } + results, err := q.GetAccountSignersByAccountID(account) + tt.Assert.NoError(err) + tt.Assert.Len(results, 2) + tt.Assert.Equal(expected, results) +} diff --git a/services/horizon/internal/db2/history/accounts_test.go b/services/horizon/internal/db2/history/accounts_test.go index c6313d2d1e..be65465c04 100644 --- a/services/horizon/internal/db2/history/accounts_test.go +++ b/services/horizon/internal/db2/history/accounts_test.go @@ -307,3 +307,31 @@ func TestAccountEntriesForSigner(t *testing.T) { assert.NoError(t, err) tt.Assert.Len(accounts, 2) } + +func TestGetAccountByID(t *testing.T) { + tt := test.Start(t) + defer tt.Finish() + test.ResetHorizonDB(t, tt.HorizonDB) + q := &Q{tt.HorizonSession()} + + _, err := q.InsertAccount(account1, 1234) + tt.Assert.NoError(err) + + resultAccount, err := q.GetAccountByID(account1.AccountId.Address()) + assert.NoError(t, err) + assert.NoError(t, err) + + assert.Equal(t, "GAOQJGUAB7NI7K7I62ORBXMN3J4SSWQUQ7FOEPSDJ322W2HMCNWPHXFB", resultAccount.AccountID) + assert.Equal(t, int64(20000), resultAccount.Balance) + assert.Equal(t, int64(223456789), resultAccount.SequenceNumber) + assert.Equal(t, uint32(10), resultAccount.NumSubEntries) + assert.Equal(t, "GBUH7T6U36DAVEKECMKN5YEBQYZVRBPNSZAAKBCO6P5HBMDFSQMQL4Z4", resultAccount.InflationDestination) + assert.Equal(t, uint32(1), resultAccount.Flags) + assert.Equal(t, "stellar.org", resultAccount.HomeDomain) + assert.Equal(t, byte(1), resultAccount.MasterWeight) + assert.Equal(t, byte(2), resultAccount.ThresholdLow) + assert.Equal(t, byte(3), resultAccount.ThresholdMedium) + assert.Equal(t, byte(4), resultAccount.ThresholdHigh) + assert.Equal(t, int64(3), resultAccount.BuyingLiabilities) + assert.Equal(t, int64(4), resultAccount.SellingLiabilities) +} diff --git a/services/horizon/internal/db2/history/trust_lines_test.go b/services/horizon/internal/db2/history/trust_lines_test.go index 5fa0a73dae..b5054e2474 100644 --- a/services/horizon/internal/db2/history/trust_lines_test.go +++ b/services/horizon/internal/db2/history/trust_lines_test.go @@ -211,3 +211,26 @@ func TestGetTrustLinesByAccountsID(t *testing.T) { tt.Assert.Len(m, 0) } + +func TestGetTrustLinesByAccountID(t *testing.T) { + tt := test.Start(t) + defer tt.Finish() + test.ResetHorizonDB(t, tt.HorizonDB) + q := &Q{tt.HorizonSession()} + + _, err := q.InsertTrustLine(eurTrustLine, 1234) + tt.Assert.NoError(err) + + record, err := q.GetTrustLinesByAccountID(eurTrustLine.AccountId.Address()) + tt.Assert.NoError(err) + + asset := xdr.MustNewCreditAsset(record[0].AssetCode, record[0].AssetIssuer) + tt.Assert.Equal(eurTrustLine.Asset, asset) + tt.Assert.Equal(eurTrustLine.AccountId.Address(), record[0].AccountID) + tt.Assert.Equal(int64(eurTrustLine.Balance), record[0].Balance) + tt.Assert.Equal(int64(eurTrustLine.Limit), record[0].Limit) + tt.Assert.Equal(uint32(eurTrustLine.Flags), record[0].Flags) + tt.Assert.Equal(int64(eurTrustLine.Ext.V1.Liabilities.Buying), record[0].BuyingLiabilities) + tt.Assert.Equal(int64(eurTrustLine.Ext.V1.Liabilities.Selling), record[0].SellingLiabilities) + +} From 1742a8d653bf0de54e462582ec08a4e22f1284e8 Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Wed, 30 Oct 2019 17:22:57 +0100 Subject: [PATCH 6/6] review --- .../internal/db2/history/account_data_test.go | 48 +++++++++---------- .../internal/db2/history/account_signers.go | 7 ++- .../db2/history/account_signers_test.go | 12 ++--- .../internal/db2/history/accounts_test.go | 1 - 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/services/horizon/internal/db2/history/account_data_test.go b/services/horizon/internal/db2/history/account_data_test.go index 41861cb2c2..db29cb41e5 100644 --- a/services/horizon/internal/db2/history/account_data_test.go +++ b/services/horizon/internal/db2/history/account_data_test.go @@ -31,11 +31,11 @@ func TestInsertAccountData(t *testing.T) { rows, err := q.InsertAccountData(data1, 1234) assert.NoError(t, err) - assert.Equal(t, int64(1), rows) + tt.Assert.Equal(int64(1), rows) rows, err = q.InsertAccountData(data2, 1235) assert.NoError(t, err) - assert.Equal(t, int64(1), rows) + tt.Assert.Equal(int64(1), rows) keys := []xdr.LedgerKeyData{ {AccountId: data1.AccountId, DataName: data1.DataName}, @@ -46,11 +46,11 @@ func TestInsertAccountData(t *testing.T) { assert.NoError(t, err) assert.Len(t, datas, 2) - assert.Equal(t, data1.DataName, xdr.String64(datas[0].Name)) - assert.Equal(t, []byte(data1.DataValue), []byte(datas[0].Value)) + tt.Assert.Equal(data1.DataName, xdr.String64(datas[0].Name)) + tt.Assert.Equal([]byte(data1.DataValue), []byte(datas[0].Value)) - assert.Equal(t, data2.DataName, xdr.String64(datas[1].Name)) - assert.Equal(t, []byte(data2.DataValue), []byte(datas[1].Value)) + tt.Assert.Equal(data2.DataName, xdr.String64(datas[1].Name)) + tt.Assert.Equal([]byte(data2.DataValue), []byte(datas[1].Value)) } func TestUpdateAccountData(t *testing.T) { @@ -61,14 +61,14 @@ func TestUpdateAccountData(t *testing.T) { rows, err := q.InsertAccountData(data1, 1234) assert.NoError(t, err) - assert.Equal(t, int64(1), rows) + tt.Assert.Equal(int64(1), rows) modifiedData := data1 modifiedData.DataValue[0] = 1 rows, err = q.UpdateAccountData(modifiedData, 1235) assert.NoError(t, err) - assert.Equal(t, int64(1), rows) + tt.Assert.Equal(int64(1), rows) keys := []xdr.LedgerKeyData{ {AccountId: data1.AccountId, DataName: data1.DataName}, @@ -77,9 +77,9 @@ func TestUpdateAccountData(t *testing.T) { assert.NoError(t, err) assert.Len(t, datas, 1) - assert.Equal(t, modifiedData.DataName, xdr.String64(datas[0].Name)) - assert.Equal(t, []byte(modifiedData.DataValue), []byte(datas[0].Value)) - assert.Equal(t, uint32(1235), datas[0].LastModifiedLedger) + tt.Assert.Equal(modifiedData.DataName, xdr.String64(datas[0].Name)) + tt.Assert.Equal([]byte(modifiedData.DataValue), []byte(datas[0].Value)) + tt.Assert.Equal(uint32(1235), datas[0].LastModifiedLedger) } func TestRemoveAccountData(t *testing.T) { @@ -90,12 +90,12 @@ func TestRemoveAccountData(t *testing.T) { rows, err := q.InsertAccountData(data1, 1234) assert.NoError(t, err) - assert.Equal(t, int64(1), rows) + tt.Assert.Equal(int64(1), rows) key := xdr.LedgerKeyData{AccountId: data1.AccountId, DataName: data1.DataName} rows, err = q.RemoveAccountData(key) assert.NoError(t, err) - assert.Equal(t, int64(1), rows) + tt.Assert.Equal(int64(1), rows) datas, err := q.GetAccountDataByKeys([]xdr.LedgerKeyData{key}) assert.NoError(t, err) @@ -104,7 +104,7 @@ func TestRemoveAccountData(t *testing.T) { // Doesn't exist anymore rows, err = q.RemoveAccountData(key) assert.NoError(t, err) - assert.Equal(t, int64(0), rows) + tt.Assert.Equal(int64(0), rows) } func TestGetAccountDataByAccountsID(t *testing.T) { @@ -126,11 +126,11 @@ func TestGetAccountDataByAccountsID(t *testing.T) { assert.NoError(t, err) assert.Len(t, datas, 2) - assert.Equal(t, data1.DataName, xdr.String64(datas[0].Name)) - assert.Equal(t, []byte(data1.DataValue), []byte(datas[0].Value)) + tt.Assert.Equal(data1.DataName, xdr.String64(datas[0].Name)) + tt.Assert.Equal([]byte(data1.DataValue), []byte(datas[0].Value)) - assert.Equal(t, data2.DataName, xdr.String64(datas[1].Name)) - assert.Equal(t, []byte(data2.DataValue), []byte(datas[1].Value)) + tt.Assert.Equal(data2.DataName, xdr.String64(datas[1].Name)) + tt.Assert.Equal([]byte(data2.DataValue), []byte(datas[1].Value)) } func TestGetAccountDataByAccountID(t *testing.T) { @@ -144,13 +144,13 @@ func TestGetAccountDataByAccountID(t *testing.T) { _, err = q.InsertAccountData(data2, 1235) assert.NoError(t, err) - datas, err := q.GetAccountDataByAccountID(data1.AccountId.Address()) + records, err := q.GetAccountDataByAccountID(data1.AccountId.Address()) assert.NoError(t, err) - assert.Len(t, datas, 2) + assert.Len(t, records, 2) - assert.Equal(t, data1.DataName, xdr.String64(datas[0].Name)) - assert.Equal(t, []byte(data1.DataValue), []byte(datas[0].Value)) + tt.Assert.Equal(data1.DataName, xdr.String64(records[0].Name)) + tt.Assert.Equal([]byte(data1.DataValue), []byte(records[0].Value)) - assert.Equal(t, data2.DataName, xdr.String64(datas[1].Name)) - assert.Equal(t, []byte(data2.DataValue), []byte(datas[1].Value)) + tt.Assert.Equal(data2.DataName, xdr.String64(records[1].Name)) + tt.Assert.Equal([]byte(data2.DataValue), []byte(records[1].Value)) } diff --git a/services/horizon/internal/db2/history/account_signers.go b/services/horizon/internal/db2/history/account_signers.go index 2baed212c7..c8b8d693e2 100644 --- a/services/horizon/internal/db2/history/account_signers.go +++ b/services/horizon/internal/db2/history/account_signers.go @@ -8,7 +8,9 @@ import ( ) func (q *Q) GetAccountSignersByAccountID(id string) ([]AccountSigner, error) { - sql := selectAccountSigners.Where(sq.Eq{"accounts_signers.account": id}) + sql := selectAccountSigners. + Where(sq.Eq{"accounts_signers.account": id}). + OrderBy("accounts_signers.signer asc") var results []AccountSigner if err := q.Select(&results, sql); err != nil { @@ -19,7 +21,8 @@ func (q *Q) GetAccountSignersByAccountID(id string) ([]AccountSigner, error) { } func (q *Q) SignersForAccounts(accounts []string) ([]AccountSigner, error) { - sql := selectAccountSigners.Where(map[string]interface{}{"accounts_signers.account": accounts}) + sql := selectAccountSigners. + Where(map[string]interface{}{"accounts_signers.account": accounts}) var results []AccountSigner if err := q.Select(&results, sql); err != nil { diff --git a/services/horizon/internal/db2/history/account_signers_test.go b/services/horizon/internal/db2/history/account_signers_test.go index cc3f116105..a93f48a293 100644 --- a/services/horizon/internal/db2/history/account_signers_test.go +++ b/services/horizon/internal/db2/history/account_signers_test.go @@ -130,12 +130,12 @@ func TestGetAccountSignersByAccountID(t *testing.T) { q := &Q{tt.HorizonSession()} account := "GA5WBPYA5Y4WAEHXWR2UKO2UO4BUGHUQ74EUPKON2QHV4WRHOIRNKKH6" - signer := "GC2WJF6YWMAEHGGAK2UOMZCIOMH4RU7KY2CQEWZQJV2ZQJVXJ335ZSXG" + signer := "GC23QF2HUE52AMXUFUH3AYJAXXGXXV2VHXYYR6EYXETPKDXZSAW67XO7" weight := int32(123) _, err := q.CreateAccountSigner(account, signer, weight) tt.Assert.NoError(err) - signer2 := "GC23QF2HUE52AMXUFUH3AYJAXXGXXV2VHXYYR6EYXETPKDXZSAW67XO7" + signer2 := "GC2WJF6YWMAEHGGAK2UOMZCIOMH4RU7KY2CQEWZQJV2ZQJVXJ335ZSXG" weight2 := int32(100) _, err = q.CreateAccountSigner(account, signer2, weight2) tt.Assert.NoError(err) @@ -143,13 +143,13 @@ func TestGetAccountSignersByAccountID(t *testing.T) { expected := []AccountSigner{ AccountSigner{ Account: account, - Signer: signer2, - Weight: weight2, + Signer: signer, + Weight: weight, }, AccountSigner{ Account: account, - Signer: signer, - Weight: weight, + Signer: signer2, + Weight: weight2, }, } results, err := q.GetAccountSignersByAccountID(account) diff --git a/services/horizon/internal/db2/history/accounts_test.go b/services/horizon/internal/db2/history/accounts_test.go index be65465c04..65112f2505 100644 --- a/services/horizon/internal/db2/history/accounts_test.go +++ b/services/horizon/internal/db2/history/accounts_test.go @@ -319,7 +319,6 @@ func TestGetAccountByID(t *testing.T) { resultAccount, err := q.GetAccountByID(account1.AccountId.Address()) assert.NoError(t, err) - assert.NoError(t, err) assert.Equal(t, "GAOQJGUAB7NI7K7I62ORBXMN3J4SSWQUQ7FOEPSDJ322W2HMCNWPHXFB", resultAccount.AccountID) assert.Equal(t, int64(20000), resultAccount.Balance)