diff --git a/services/horizon/internal/action.go b/services/horizon/internal/action.go index 3eea4b6ad1..1644118845 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" @@ -175,7 +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) { - return actions.AccountInfo(ctx, &core.Q{w.coreSession(ctx)}, qp.AccountID) + // 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, "error starting transaction") + } + + defer horizonSession.Rollback() + historyQ = &history.Q{horizonSession} + } + + 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 96ee639b4c..df14283c04 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,13 +11,14 @@ 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" "github.com/stellar/go/support/render/problem" "github.com/stellar/go/xdr" ) // 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, enableExperimentalIngestion bool) (*protocol.Account, error) { var ( coreRecord core.Account coreData []core.AccountData @@ -52,8 +55,200 @@ func AccountInfo(ctx context.Context, cq *core.Q, addr string) (*protocol.Accoun coreSigners, coreTrustlines, ) + if err != nil { + return nil, errors.Wrap(err, "populating account") + } + + 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` 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 +} + +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 + } - return &resource, errors.Wrap(err, "populating account") + 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 nil } // AccountsQuery query struct for accounts end-point diff --git a/services/horizon/internal/actions/account_test.go b/services/horizon/internal/actions/account_test.go index 94bc25d0b3..a00f3c14ec 100644 --- a/services/horizon/internal/actions/account_test.go +++ b/services/horizon/internal/actions/account_test.go @@ -159,7 +159,13 @@ func TestAccountInfo(t *testing.T) { tt := test.Start(t).Scenario("allow_trust") defer tt.Finish() - account, err := AccountInfo(tt.Ctx, &core.Q{tt.CoreSession()}, signer) + account, err := AccountInfo( + tt.Ctx, + &core.Q{tt.CoreSession()}, + &history.Q{tt.HorizonSession()}, + signer, + false, + ) 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 65b40ad3de..dd3d834b43 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_test.go b/services/horizon/internal/db2/history/account_data_test.go index b94aaba036..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,9 +126,31 @@ 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) { + 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) + + records, err := q.GetAccountDataByAccountID(data1.AccountId.Address()) + assert.NoError(t, err) + assert.Len(t, records, 2) + + tt.Assert.Equal(data1.DataName, xdr.String64(records[0].Name)) + tt.Assert.Equal([]byte(data1.DataValue), []byte(records[0].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_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 caba172023..c8b8d693e2 100644 --- a/services/horizon/internal/db2/history/account_signers.go +++ b/services/horizon/internal/db2/history/account_signers.go @@ -7,8 +7,22 @@ import ( "github.com/stellar/go/support/errors" ) +func (q *Q) GetAccountSignersByAccountID(id string) ([]AccountSigner, error) { + 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 { + 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}) + 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 7b68c631bb..a93f48a293 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 := "GC23QF2HUE52AMXUFUH3AYJAXXGXXV2VHXYYR6EYXETPKDXZSAW67XO7" + weight := int32(123) + _, err := q.CreateAccountSigner(account, signer, weight) + tt.Assert.NoError(err) + + signer2 := "GC2WJF6YWMAEHGGAK2UOMZCIOMH4RU7KY2CQEWZQJV2ZQJVXJ335ZSXG" + weight2 := int32(100) + _, err = q.CreateAccountSigner(account, signer2, weight2) + tt.Assert.NoError(err) + + expected := []AccountSigner{ + AccountSigner{ + Account: account, + Signer: signer, + Weight: weight, + }, + AccountSigner{ + Account: account, + Signer: signer2, + Weight: weight2, + }, + } + 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.go b/services/horizon/internal/db2/history/accounts.go index cb869639ea..c1845b6125 100644 --- a/services/horizon/internal/db2/history/accounts.go +++ b/services/horizon/internal/db2/history/accounts.go @@ -37,6 +37,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/accounts_test.go b/services/horizon/internal/db2/history/accounts_test.go index c6313d2d1e..65112f2505 100644 --- a/services/horizon/internal/db2/history/accounts_test.go +++ b/services/horizon/internal/db2/history/accounts_test.go @@ -307,3 +307,30 @@ 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.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.go b/services/horizon/internal/db2/history/trust_lines.go index 13c6468d19..3eb25bc28b 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/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) + +} 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] +}