Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

all: Update libs & tests to support ScValue overhaul. #4819

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04]
go: [1.19.4]
# lmao semvers aren't floats never 4get
go: ["1.19", "1.20"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
Expand All @@ -38,7 +39,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04]
go: [1.18.6, 1.19.4]
go: ["1.19", "1.20"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
Expand All @@ -56,7 +57,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04]
go: [1.18.6, 1.19.4]
go: ["1.19", "1.20"]
pg: [9.6.5, 10]
runs-on: ${{ matrix.os }}
services:
Expand All @@ -82,7 +83,7 @@ jobs:
--health-retries 5
ports:
- 6379:6379
env:
env:
PGHOST: localhost
PGPORT: 5432
PGUSER: postgres
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/horizon-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

- uses: ./.github/actions/setup-go
with:
go-version: 1.19.4
go-version: "1.20"

- name: Check dependencies
run: ./gomod.sh
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/horizon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04]
go: [1.18.6, 1.19.4]
go: ["1.19", "1.20"]
pg: [9.6.5]
ingestion-backend: [db, captive-core, captive-core-remote-storage]
protocol-version: [19, 20]
Expand All @@ -34,8 +34,8 @@ jobs:
env:
HORIZON_INTEGRATION_TESTS_ENABLED: true
HORIZON_INTEGRATION_TESTS_CORE_MAX_SUPPORTED_PROTOCOL: ${{ matrix.protocol-version }}
PROTOCOL_20_CORE_DEBIAN_PKG_VERSION: 19.8.1-1234.f94d66031.focal~soroban
PROTOCOL_20_CORE_DOCKER_IMG: gkudra/stellar-core:19.8.1-1234.f94d66031.focal-soroban
PROTOCOL_20_CORE_DEBIAN_PKG_VERSION: 19.8.1-1243.53ea43ace.focal~soroban
PROTOCOL_20_CORE_DOCKER_IMG: 2opremio/stellar-core:19.8.1-1243.53ea43ace.focal-soroban
PROTOCOL_19_CORE_DEBIAN_PKG_VERSION: 19.5.0-1108.ca2fb0605.focal
PROTOCOL_19_CORE_DOCKER_IMG: stellar/stellar-core:19.5.0-1108.ca2fb0605.focal
PGHOST: localhost
Expand Down
16 changes: 16 additions & 0 deletions amount/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,22 @@ func String(v xdr.Int64) string {
return StringFromInt64(int64(v))
}

// String128 converts a signed 128-bit integer into a string, boldly assuming
// 7-decimal precision.
//
// TODO: This should be adapted to variable precision when appopriate, but 7
// decimals is the correct default for Stellar Classic amounts.
func String128(v xdr.Int128Parts) string {
// the upper half of the i128 always indicates its sign regardless of its
// value, just like a native signed type
val := big.NewInt(int64(v.Hi))
val.Lsh(val, 64).Add(val, new(big.Int).SetUint64(uint64(v.Lo)))

rat := new(big.Rat).SetInt(val)
rat.Quo(rat, bigOne)
return rat.FloatString(7)
}

// StringFromInt64 returns an "amount string" from the provided raw int64 value `v`.
func StringFromInt64(v int64) string {
r := big.NewRat(v, 1)
Expand Down
39 changes: 34 additions & 5 deletions protocols/horizon/operations/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,13 +348,23 @@ type LiquidityPoolWithdraw struct {
// InvokeHostFunction is the json resource representing a single smart contract
// function invocation operation, having type InvokeHostFunction.
//
// The model for InvokeHostFunction is intentionally simplified, Footprint
// just contains a base64 encoded string of it's xdr serialization.
// The model for InvokeHostFunction is intentionally simplified.
// Parameters - array of tuples of each function input parameter value and it's data type
// Function - name of contract function
// Footprint - base64 encoded string of it's xdr serialization.
// AssetBalanceChanges - array of asset balance changed records.
// The asset balance change record is captured at ingestion time from the asset contract
// events present in tx meta. Only asset contract events that have a reference to classic account in
// either the 'from' or 'to' participants will be included here as an asset balance change.
// Any pure contract-to-contract events with no reference to classic accounts are not included,
// as there is no explicit model in horizon for contract addresses yet.

type InvokeHostFunction struct {
Base
Parameters []HostFunctionParameter `json:"parameters"`
Function string `json:"function"`
Footprint string `json:"footprint"`
Parameters []HostFunctionParameter `json:"parameters"`
Function string `json:"function"`
Footprint string `json:"footprint"`
AssetBalanceChanges []AssetContractBalanceChange `json:"asset_balance_changes"`
}

// InvokeHostFunction parameter model, intentionally simplified, Value
Expand All @@ -364,6 +374,25 @@ type HostFunctionParameter struct {
Type string `json:"type"`
}

// Type - refers to the source SAC Event
//
// it can only be one of 'transfer', 'mint', 'clawback' or 'burn'
//
// From - this is classic account that asset balance was changed.
// To - this is the classic account that asset balance was changed, or if not applicable
//
// for asset contract event type, it can be absent such as 'burn'
//
// Amount - expressed as a signed decimal to 7 digits precision.
// Asset - the classic asset expressed as issuer and code.
type AssetContractBalanceChange struct {
base.Asset
Type string `json:"type"`
From string `json:"from"`
To string `json:"to,omitempty"`
Amount string `json:"amount"`
}

// Operation interface contains methods implemented by the operation types
type Operation interface {
GetBase() Base
Expand Down
172 changes: 172 additions & 0 deletions services/horizon/internal/actions/operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,156 @@ package actions

import (
"database/sql"
"encoding/hex"
"fmt"
"net/http/httptest"
"testing"
"time"

"github.com/guregu/null"
"github.com/stellar/go/ingest"
"github.com/stellar/go/protocols/horizon/operations"
"github.com/stellar/go/services/horizon/internal/db2/history"
"github.com/stellar/go/services/horizon/internal/ledger"
"github.com/stellar/go/services/horizon/internal/render/problem"
"github.com/stellar/go/services/horizon/internal/test"
supportProblem "github.com/stellar/go/support/render/problem"
"github.com/stellar/go/toid"
"github.com/stellar/go/xdr"
"github.com/stretchr/testify/assert"
)

func TestInvokeHostFnDetailsInPaymentOperations(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
test.ResetHorizonDB(t, tt.HorizonDB)

q := &history.Q{tt.HorizonSession()}
handler := GetOperationsHandler{OnlyPayments: true}

txIndex := int32(1)
sequence := int32(56)
txID := toid.New(sequence, txIndex, 0).ToInt64()
opID1 := toid.New(sequence, txIndex, 1).ToInt64()

ledgerCloseTime := time.Now().Unix()
_, err := q.InsertLedger(tt.Ctx, xdr.LedgerHeaderHistoryEntry{
Header: xdr.LedgerHeader{
LedgerSeq: xdr.Uint32(sequence),
ScpValue: xdr.StellarValue{
CloseTime: xdr.TimePoint(ledgerCloseTime),
},
},
}, 1, 0, 1, 0, 0)
tt.Assert.NoError(err)

transactionBuilder := q.NewTransactionBatchInsertBuilder(1)
firstTransaction := buildLedgerTransaction(tt.T, testTransaction{
index: uint32(txIndex),
envelopeXDR: "AAAAACiSTRmpH6bHC6Ekna5e82oiGY5vKDEEUgkq9CB//t+rAAAAyAEXUhsAADDRAAAAAAAAAAAAAAABAAAAAAAAAAsBF1IbAABX4QAAAAAAAAAA",
resultXDR: "AAAAAAAAASwAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAFAAAAAAAAAAA=",
feeChangesXDR: "AAAAAA==",
metaXDR: "AAAAAQAAAAAAAAAA",
hash: "19aaa18db88605aedec04659fb45e06f240b022eb2d429e05133e4d53cd945ba",
})
err = transactionBuilder.Add(tt.Ctx, firstTransaction, uint32(sequence))
tt.Assert.NoError(err)

operationBuilder := q.NewOperationBatchInsertBuilder(1)
err = operationBuilder.Add(tt.Ctx,
opID1,
txID,
1,
xdr.OperationTypeInvokeHostFunction,
[]byte(`{
"parameters": [],
"function": "fn",
"footprint": "",
"asset_balance_changes": [
{
"asset_type": "credit_alphanum4",
"asset_code": "abc",
"asset_issuer": "123",
"from": "C_CONTRACT_ADDRESS1",
"to": "G_CLASSIC_ADDRESS1",
"amount": "3",
"type": "transfer"
},
{
"asset_type": "credit_alphanum4",
"asset_code": "abc",
"asset_issuer": "123",
"from": "G_CLASSIC_ADDRESS2",
"to": "G_CLASSIC_ADDRESS3",
"amount": "5",
"type": "clawback"
},
{
"asset_type": "credit_alphanum4",
"asset_code": "abc",
"asset_issuer": "123",
"from": "G_CLASSIC_ADDRESS2",
"amount": "6",
"type": "burn"
},
{
"asset_type": "credit_alphanum4",
"asset_code": "abc",
"asset_issuer": "123",
"from": "G_CLASSIC_ADDRESS2",
"to": "C_CONTRACT_ADDRESS3",
"amount": "10",
"type": "mint"
}
]
}`),
"GAUJETIZVEP2NRYLUESJ3LS66NVCEGMON4UDCBCSBEVPIID773P2W6AY",
null.String{},
true)
tt.Assert.NoError(err)

records, err := handler.GetResourcePage(
httptest.NewRecorder(),
makeRequest(
t, map[string]string{}, map[string]string{}, q,
),
)
tt.Assert.NoError(err)
tt.Assert.Len(records, 1)

op := records[0].(operations.InvokeHostFunction)
tt.Assert.Equal(op.Function, "fn")
tt.Assert.Equal(len(op.AssetBalanceChanges), 4)
tt.Assert.Equal(op.AssetBalanceChanges[0].From, "C_CONTRACT_ADDRESS1")
tt.Assert.Equal(op.AssetBalanceChanges[0].To, "G_CLASSIC_ADDRESS1")
tt.Assert.Equal(op.AssetBalanceChanges[0].Amount, "3")
tt.Assert.Equal(op.AssetBalanceChanges[0].Type, "transfer")
tt.Assert.Equal(op.AssetBalanceChanges[0].Asset.Type, "credit_alphanum4")
tt.Assert.Equal(op.AssetBalanceChanges[0].Asset.Code, "abc")
tt.Assert.Equal(op.AssetBalanceChanges[0].Asset.Issuer, "123")
tt.Assert.Equal(op.AssetBalanceChanges[1].From, "G_CLASSIC_ADDRESS2")
tt.Assert.Equal(op.AssetBalanceChanges[1].To, "G_CLASSIC_ADDRESS3")
tt.Assert.Equal(op.AssetBalanceChanges[1].Amount, "5")
tt.Assert.Equal(op.AssetBalanceChanges[1].Type, "clawback")
tt.Assert.Equal(op.AssetBalanceChanges[1].Asset.Type, "credit_alphanum4")
tt.Assert.Equal(op.AssetBalanceChanges[1].Asset.Code, "abc")
tt.Assert.Equal(op.AssetBalanceChanges[1].Asset.Issuer, "123")
tt.Assert.Equal(op.AssetBalanceChanges[2].From, "G_CLASSIC_ADDRESS2")
tt.Assert.Equal(op.AssetBalanceChanges[2].To, "")
tt.Assert.Equal(op.AssetBalanceChanges[2].Amount, "6")
tt.Assert.Equal(op.AssetBalanceChanges[2].Type, "burn")
tt.Assert.Equal(op.AssetBalanceChanges[2].Asset.Type, "credit_alphanum4")
tt.Assert.Equal(op.AssetBalanceChanges[2].Asset.Code, "abc")
tt.Assert.Equal(op.AssetBalanceChanges[2].Asset.Issuer, "123")
tt.Assert.Equal(op.AssetBalanceChanges[3].From, "G_CLASSIC_ADDRESS2")
tt.Assert.Equal(op.AssetBalanceChanges[3].To, "C_CONTRACT_ADDRESS3")
tt.Assert.Equal(op.AssetBalanceChanges[3].Amount, "10")
tt.Assert.Equal(op.AssetBalanceChanges[3].Type, "mint")
tt.Assert.Equal(op.AssetBalanceChanges[3].Asset.Type, "credit_alphanum4")
tt.Assert.Equal(op.AssetBalanceChanges[3].Asset.Code, "abc")
tt.Assert.Equal(op.AssetBalanceChanges[3].Asset.Issuer, "123")
}

func TestGetOperationsWithoutFilter(t *testing.T) {
tt := test.Start(t)
defer tt.Finish()
Expand Down Expand Up @@ -695,3 +832,38 @@ func TestOperation_IncludeTransaction(t *testing.T) {
tt.Assert.NotNil(op.Transaction)
tt.Assert.Equal(op.TransactionHash, op.Transaction.ID)
}

type testTransaction struct {
index uint32
envelopeXDR string
resultXDR string
feeChangesXDR string
metaXDR string
hash string
}

func buildLedgerTransaction(t *testing.T, tx testTransaction) ingest.LedgerTransaction {
transaction := ingest.LedgerTransaction{
Index: tx.index,
Envelope: xdr.TransactionEnvelope{},
Result: xdr.TransactionResultPair{},
FeeChanges: xdr.LedgerEntryChanges{},
UnsafeMeta: xdr.TransactionMeta{},
}

tt := assert.New(t)

err := xdr.SafeUnmarshalBase64(tx.envelopeXDR, &transaction.Envelope)
tt.NoError(err)
err = xdr.SafeUnmarshalBase64(tx.resultXDR, &transaction.Result.Result)
tt.NoError(err)
err = xdr.SafeUnmarshalBase64(tx.metaXDR, &transaction.UnsafeMeta)
tt.NoError(err)
err = xdr.SafeUnmarshalBase64(tx.feeChangesXDR, &transaction.FeeChanges)
tt.NoError(err)

_, err = hex.Decode(transaction.Result.TransactionHash[:], []byte(tx.hash))
tt.NoError(err)

return transaction
}
1 change: 1 addition & 0 deletions services/horizon/internal/db2/history/fee_bump_scenario.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ func FeeBumpScenario(tt *test.T, q *Q, successful bool) FeeBumpFixture {
details,
account.Address(),
null.String{},
false,
))
tt.Assert.NoError(opBuilder.Exec(ctx))

Expand Down
16 changes: 13 additions & 3 deletions services/horizon/internal/db2/history/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,20 @@ const (
// EffectAccountRemoved effects occur when one account is merged into another
EffectAccountRemoved EffectType = 1 // from merge_account

// EffectAccountCredited effects occur when an account receives some currency
EffectAccountCredited EffectType = 2 // from create_account, payment, path_payment, merge_account
// EffectAccountCredited effects occur when an account receives some
// currency
//
// from create_account, payment, path_payment, merge_account, and SAC events
// involving transfers, mints, and burns.
EffectAccountCredited EffectType = 2

// EffectAccountDebited effects occur when an account sends some currency
EffectAccountDebited EffectType = 3 // from create_account, payment, path_payment, create_account
//
// from create_account, payment, path_payment, create_account, and SAC
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge_account as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dunno, this comment was left as-is. I read it as "the merged account doesn't get a debit effect it just disappears"?

// involving transfers, mints, and burns.
//
// https://github.com/stellar/rs-soroban-env/blob/5695440da452837555d8f7f259cc33341fdf07b0/soroban-env-host/src/native_contract/token/contract.rs#L51-L63
EffectAccountDebited EffectType = 3

// EffectAccountThresholdsUpdated effects occur when an account changes its
// multisig thresholds.
Expand Down Expand Up @@ -664,6 +673,7 @@ type Operation struct {
SourceAccount string `db:"source_account"`
SourceAccountMuxed null.String `db:"source_account_muxed"`
TransactionSuccessful bool `db:"transaction_successful"`
IsPayment bool `db:"is_payment"`
}

// ManageOffer is a struct of data from `operations.DetailsString`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func (m *MockOperationsBatchInsertBuilder) Add(ctx context.Context,
details []byte,
sourceAccount string,
sourceAccountMuxed null.String,
isPayment bool,
) error {
a := m.Called(ctx,
id,
Expand All @@ -31,6 +32,7 @@ func (m *MockOperationsBatchInsertBuilder) Add(ctx context.Context,
details,
sourceAccount,
sourceAccountMuxed,
isPayment,
)
return a.Error(0)
}
Expand Down
Loading