diff --git a/.github/workflows/horizon.yml b/.github/workflows/horizon.yml index 6b901b7b7e..021fc4fc9f 100644 --- a/.github/workflows/horizon.yml +++ b/.github/workflows/horizon.yml @@ -34,10 +34,10 @@ jobs: env: HORIZON_INTEGRATION_TESTS_ENABLED: true HORIZON_INTEGRATION_TESTS_CORE_MAX_SUPPORTED_PROTOCOL: ${{ matrix.protocol-version }} - PROTOCOL_19_CORE_DEBIAN_PKG_VERSION: 19.0.0-891.rc1.9d0704eb4.focal - PROTOCOL_19_CORE_DOCKER_IMG: stellar/stellar-core:19.0.0-891.rc1.9d0704eb4.focal - PROTOCOL_18_CORE_DEBIAN_PKG_VERSION: 18.5.0-873.rc1.d387c6a71.focal - PROTOCOL_18_CORE_DOCKER_IMG: stellar/stellar-core:18.5.0-873.rc1.d387c6a71.focal + PROTOCOL_19_CORE_DEBIAN_PKG_VERSION: 19.0.0-907.9d0704eb4.focal + PROTOCOL_19_CORE_DOCKER_IMG: stellar/stellar-core:19.0.0-907.9d0704eb4.focal + PROTOCOL_18_CORE_DEBIAN_PKG_VERSION: 19.0.0-907.9d0704eb4.focal + PROTOCOL_18_CORE_DOCKER_IMG: stellar/stellar-core:19.0.0-907.9d0704eb4.focal PGHOST: localhost PGPORT: 5432 PGUSER: postgres diff --git a/gxdr/xdr_generated.go b/gxdr/xdr_generated.go index ff20939b27..2c8d430dc4 100644 --- a/gxdr/xdr_generated.go +++ b/gxdr/xdr_generated.go @@ -419,7 +419,8 @@ type XdrAnon_TrustLineEntry_Ext_V1_Ext struct { type OfferEntryFlags int32 const ( - // an offer with this flag will not act on and take a reverse offer of equal price + // an offer with this flag will not act on and take a reverse offer of equal + // price PASSIVE_FLAG OfferEntryFlags = 1 ) @@ -618,7 +619,7 @@ type XdrAnon_LiquidityPoolEntry_Body_ConstantProduct struct { ReserveB Int64 // total number of pool shares issued TotalPoolShares Int64 - // number of trust lines for the associated pool shares + // number of trust lines for the PoolSharesTrustLineCount Int64 } @@ -2919,8 +2920,10 @@ const ( TxFEE_BUMP_INNER_FAILED TransactionResultCode = -13 // sponsorship not confirmed TxBAD_SPONSORSHIP TransactionResultCode = -14 - //minSeqAge or minSeqLedgerGap conditions not met + // minSeqAge or minSeqLedgerGap conditions not met TxBAD_MIN_SEQ_AGE_OR_GAP TransactionResultCode = -15 + // precondition is invalid + TxMALFORMED TransactionResultCode = -16 ) // InnerTransactionResult must be binary compatible with TransactionResult @@ -2935,7 +2938,7 @@ type XdrAnon_InnerTransactionResult_Result struct { // The union discriminant Code selects among the following arms: // TxSUCCESS, TxFAILED: // Results() *[]OperationResult - // TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP: + // TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP, TxMALFORMED: // void Code TransactionResultCode _u interface{} @@ -18400,6 +18403,7 @@ var _XdrNames_TransactionResultCode = map[int32]string{ int32(TxFEE_BUMP_INNER_FAILED): "txFEE_BUMP_INNER_FAILED", int32(TxBAD_SPONSORSHIP): "txBAD_SPONSORSHIP", int32(TxBAD_MIN_SEQ_AGE_OR_GAP): "txBAD_MIN_SEQ_AGE_OR_GAP", + int32(TxMALFORMED): "txMALFORMED", } var _XdrValues_TransactionResultCode = map[string]int32{ "txFEE_BUMP_INNER_SUCCESS": int32(TxFEE_BUMP_INNER_SUCCESS), @@ -18419,6 +18423,7 @@ var _XdrValues_TransactionResultCode = map[string]int32{ "txFEE_BUMP_INNER_FAILED": int32(TxFEE_BUMP_INNER_FAILED), "txBAD_SPONSORSHIP": int32(TxBAD_SPONSORSHIP), "txBAD_MIN_SEQ_AGE_OR_GAP": int32(TxBAD_MIN_SEQ_AGE_OR_GAP), + "txMALFORMED": int32(TxMALFORMED), } func (TransactionResultCode) XdrEnumNames() map[int32]string { @@ -18475,6 +18480,7 @@ var _XdrComments_TransactionResultCode = map[int32]string{ int32(TxFEE_BUMP_INNER_FAILED): "fee bump inner transaction failed", int32(TxBAD_SPONSORSHIP): "sponsorship not confirmed", int32(TxBAD_MIN_SEQ_AGE_OR_GAP): "minSeqAge or minSeqLedgerGap conditions not met", + int32(TxMALFORMED): "precondition is invalid", } func (e TransactionResultCode) XdrEnumComments() map[int32]string { @@ -18554,6 +18560,7 @@ var _XdrTags_XdrAnon_InnerTransactionResult_Result = map[int32]bool{ XdrToI32(TxNOT_SUPPORTED): true, XdrToI32(TxBAD_SPONSORSHIP): true, XdrToI32(TxBAD_MIN_SEQ_AGE_OR_GAP): true, + XdrToI32(TxMALFORMED): true, } func (_ XdrAnon_InnerTransactionResult_Result) XdrValidTags() map[int32]bool { @@ -18576,7 +18583,7 @@ func (u *XdrAnon_InnerTransactionResult_Result) Results() *[]OperationResult { } func (u XdrAnon_InnerTransactionResult_Result) XdrValid() bool { switch u.Code { - case TxSUCCESS, TxFAILED, TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP: + case TxSUCCESS, TxFAILED, TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP, TxMALFORMED: return true } return false @@ -18591,7 +18598,7 @@ func (u *XdrAnon_InnerTransactionResult_Result) XdrUnionBody() XdrType { switch u.Code { case TxSUCCESS, TxFAILED: return (*_XdrVec_unbounded_OperationResult)(u.Results()) - case TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP: + case TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP, TxMALFORMED: return nil } return nil @@ -18600,7 +18607,7 @@ func (u *XdrAnon_InnerTransactionResult_Result) XdrUnionBodyName() string { switch u.Code { case TxSUCCESS, TxFAILED: return "Results" - case TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP: + case TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP, TxMALFORMED: return "" } return "" @@ -18623,7 +18630,7 @@ func (u *XdrAnon_InnerTransactionResult_Result) XdrRecurse(x XDR, name string) { case TxSUCCESS, TxFAILED: x.Marshal(x.Sprintf("%sresults", name), (*_XdrVec_unbounded_OperationResult)(u.Results())) return - case TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP: + case TxTOO_EARLY, TxTOO_LATE, TxMISSING_OPERATION, TxBAD_SEQ, TxBAD_AUTH, TxINSUFFICIENT_BALANCE, TxNO_ACCOUNT, TxINSUFFICIENT_FEE, TxBAD_AUTH_EXTRA, TxINTERNAL_ERROR, TxNOT_SUPPORTED, TxBAD_SPONSORSHIP, TxBAD_MIN_SEQ_AGE_OR_GAP, TxMALFORMED: return } XdrPanic("invalid Code (%v) in XdrAnon_InnerTransactionResult_Result", u.Code) diff --git a/services/horizon/CHANGELOG.md b/services/horizon/CHANGELOG.md index be7a634e24..8d224dbe62 100644 --- a/services/horizon/CHANGELOG.md +++ b/services/horizon/CHANGELOG.md @@ -5,11 +5,15 @@ file. This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +## V2.17.0 Release Candidate + +**Upgrading to this version from <= v2.8.3 will trigger a state rebuild. During this process (which will take at least 10 minutes), Horizon will not ingest new ledgers.** + **Support for Protocol 19** ([4340](https://github.com/stellar/go/pull/4340)): - Account records can now contain two new, optional fields: -```json +```txt "sequence_ledger": 0, // uint32 ledger number "sequence_time": "0" // uint64 unix time in seconds, as a string ``` @@ -18,7 +22,7 @@ file. This project adheres to [Semantic Versioning](http://semver.org/). - Transaction records can now contain the following optional object: -```json +```txt "preconditions": { "timebounds": { "min_time": "0", // uint64 unix time in seconds, as a string @@ -43,7 +47,7 @@ file. This project adheres to [Semantic Versioning](http://semver.org/). ### DB Schema Migration The migration makes the following schema changes: - + - adds new, optional columns to the `history_transactions` table related to the new preconditions - adds new, optional columns to the `accounts` table related to the new account extension - amends the `signer` column of the `accounts_signers` table to allow signers of arbitrary length diff --git a/services/horizon/internal/actions/account_test.go b/services/horizon/internal/actions/account_test.go index fc384f09ae..22387406bd 100644 --- a/services/horizon/internal/actions/account_test.go +++ b/services/horizon/internal/actions/account_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/guregu/null" + "github.com/guregu/null/zero" "github.com/stretchr/testify/assert" @@ -32,8 +33,8 @@ var ( AccountID: accountOne, Balance: 20000, SequenceNumber: 223456789, - SequenceLedger: 2345, - SequenceTime: 1647265533, + SequenceLedger: zero.IntFrom(0), + SequenceTime: zero.IntFrom(0), NumSubEntries: 10, Flags: 1, HomeDomain: "stellar.org", @@ -50,8 +51,8 @@ var ( AccountID: accountTwo, Balance: 50000, SequenceNumber: 648736, - SequenceLedger: 3456, - SequenceTime: 1647365533, + SequenceLedger: zero.IntFrom(3456), + SequenceTime: zero.IntFrom(1647365533), NumSubEntries: 10, Flags: 2, HomeDomain: "meridian.stellar.org", @@ -68,8 +69,8 @@ var ( AccountID: signer, Balance: 50000, SequenceNumber: 648736, - SequenceLedger: 4567, - SequenceTime: 1647465533, + SequenceLedger: zero.IntFrom(4567), + SequenceTime: zero.IntFrom(1647465533), NumSubEntries: 10, Flags: 2, MasterWeight: 5, @@ -176,8 +177,8 @@ func TestAccountInfo(t *testing.T) { AccountID: accountID, Balance: 9999999900, SequenceNumber: 8589934593, - SequenceLedger: 4567, - SequenceTime: 1647465533, + SequenceLedger: zero.IntFrom(4567), + SequenceTime: zero.IntFrom(1647465533), NumSubEntries: 1, InflationDestination: "", HomeDomain: "", diff --git a/services/horizon/internal/codes/main.go b/services/horizon/internal/codes/main.go index 4c8f8379ee..aa342f5b58 100644 --- a/services/horizon/internal/codes/main.go +++ b/services/horizon/internal/codes/main.go @@ -74,6 +74,10 @@ func String(code interface{}) (string, error) { return "tx_internal_error", nil case xdr.TransactionResultCodeTxBadSponsorship: return "tx_bad_sponsorship", nil + case xdr.TransactionResultCodeTxBadMinSeqAgeOrGap: + return "tx_bad_minseq_age_or_gap", nil + case xdr.TransactionResultCodeTxMalformed: + return "tx_malformed", nil } case xdr.OperationResultCode: switch code { diff --git a/services/horizon/internal/db2/history/accounts_test.go b/services/horizon/internal/db2/history/accounts_test.go index 8960e3b724..ff19a0cba4 100644 --- a/services/horizon/internal/db2/history/accounts_test.go +++ b/services/horizon/internal/db2/history/accounts_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/guregu/null" + "github.com/guregu/null/zero" "github.com/stellar/go/services/horizon/internal/db2" "github.com/stellar/go/services/horizon/internal/test" "github.com/stellar/go/xdr" @@ -19,8 +20,8 @@ var ( AccountID: "GAOQJGUAB7NI7K7I62ORBXMN3J4SSWQUQ7FOEPSDJ322W2HMCNWPHXFB", Balance: 20000, SequenceNumber: 223456789, - SequenceLedger: 2345, - SequenceTime: 1647265533, + SequenceLedger: zero.IntFrom(0), + SequenceTime: zero.IntFrom(0), NumSubEntries: 10, InflationDestination: inflationDest, Flags: 1, @@ -38,8 +39,8 @@ var ( AccountID: "GCT2NQM5KJJEF55NPMY444C6M6CA7T33HRNCMA6ZFBIIXKNCRO6J25K7", Balance: 50000, SequenceNumber: 648736, - SequenceLedger: 3456, - SequenceTime: 1647365533, + SequenceLedger: zero.IntFrom(3456), + SequenceTime: zero.IntFrom(1647365533), NumSubEntries: 10, InflationDestination: inflationDest, Flags: 2, @@ -60,8 +61,8 @@ var ( AccountID: "GDPGOMFSP4IF7A4P7UBKA4UC4QTRLEHGBD6IMDIS3W3KBDNBFAQ7FXDY", Balance: 50000, SequenceNumber: 648736, - SequenceLedger: 4567, - SequenceTime: 1647465533, + SequenceLedger: zero.IntFrom(4567), + SequenceTime: zero.IntFrom(1647465533), NumSubEntries: 10, InflationDestination: inflationDest, Flags: 2, @@ -93,8 +94,8 @@ func TestInsertAccount(t *testing.T) { assert.Equal(t, "GAOQJGUAB7NI7K7I62ORBXMN3J4SSWQUQ7FOEPSDJ322W2HMCNWPHXFB", accounts[0].AccountID) assert.Equal(t, int64(20000), accounts[0].Balance) assert.Equal(t, int64(223456789), accounts[0].SequenceNumber) - assert.Equal(t, uint32(2345), accounts[0].SequenceLedger) - assert.Equal(t, uint64(1647265533), accounts[0].SequenceTime) + assert.Equal(t, zero.IntFrom(0), accounts[0].SequenceLedger) + assert.Equal(t, zero.IntFrom(0), accounts[0].SequenceTime) assert.Equal(t, uint32(10), accounts[0].NumSubEntries) assert.Equal(t, "GBUH7T6U36DAVEKECMKN5YEBQYZVRBPNSZAAKBCO6P5HBMDFSQMQL4Z4", accounts[0].InflationDestination) assert.Equal(t, uint32(1), accounts[0].Flags) @@ -129,8 +130,8 @@ func TestUpsertAccount(t *testing.T) { AccountID: "GAOQJGUAB7NI7K7I62ORBXMN3J4SSWQUQ7FOEPSDJ322W2HMCNWPHXFB", Balance: 32847893, SequenceNumber: 223456789, - SequenceTime: 223456789223456789, - SequenceLedger: 2345, + SequenceTime: zero.IntFrom(223456789223456789), + SequenceLedger: zero.IntFrom(2345), NumSubEntries: 10, InflationDestination: inflationDest, Flags: 1, @@ -458,7 +459,8 @@ func TestGetAccountByID(t *testing.T) { assert.Equal(t, "GAOQJGUAB7NI7K7I62ORBXMN3J4SSWQUQ7FOEPSDJ322W2HMCNWPHXFB", resultAccount.AccountID) assert.Equal(t, int64(20000), resultAccount.Balance) assert.Equal(t, int64(223456789), resultAccount.SequenceNumber) - assert.Equal(t, uint32(2345), resultAccount.SequenceLedger) + assert.Equal(t, zero.IntFrom(0), resultAccount.SequenceLedger) + assert.Equal(t, zero.IntFrom(0), resultAccount.SequenceTime) assert.Equal(t, uint32(10), resultAccount.NumSubEntries) assert.Equal(t, "GBUH7T6U36DAVEKECMKN5YEBQYZVRBPNSZAAKBCO6P5HBMDFSQMQL4Z4", resultAccount.InflationDestination) assert.Equal(t, uint32(1), resultAccount.Flags) diff --git a/services/horizon/internal/db2/history/main.go b/services/horizon/internal/db2/history/main.go index 69c0332719..14f0704650 100644 --- a/services/horizon/internal/db2/history/main.go +++ b/services/horizon/internal/db2/history/main.go @@ -14,6 +14,7 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/guregu/null" + "github.com/guregu/null/zero" "github.com/jmoiron/sqlx" "github.com/lib/pq" @@ -221,8 +222,8 @@ type AccountEntry struct { BuyingLiabilities int64 `db:"buying_liabilities"` SellingLiabilities int64 `db:"selling_liabilities"` SequenceNumber int64 `db:"sequence_number"` - SequenceLedger uint32 `db:"sequence_ledger"` - SequenceTime uint64 `db:"sequence_time"` + SequenceLedger zero.Int `db:"sequence_ledger"` + SequenceTime zero.Int `db:"sequence_time"` NumSubEntries uint32 `db:"num_subentries"` InflationDestination string `db:"inflation_destination"` HomeDomain string `db:"home_domain"` diff --git a/services/horizon/internal/ingest/processor_runner_test.go b/services/horizon/internal/ingest/processor_runner_test.go index 08080f277c..84b96cbe51 100644 --- a/services/horizon/internal/ingest/processor_runner_test.go +++ b/services/horizon/internal/ingest/processor_runner_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/guregu/null" + "github.com/guregu/null/zero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -30,7 +31,7 @@ func TestProcessorRunnerRunHistoryArchiveIngestionGenesis(t *testing.T) { AccountID: "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7", Balance: int64(1000000000000000000), SequenceNumber: 0, - SequenceTime: 0, + SequenceTime: zero.IntFrom(0), MasterWeight: 1, }, }).Return(nil).Once() @@ -96,7 +97,6 @@ func TestProcessorRunnerRunHistoryArchiveIngestionHistoryArchive(t *testing.T) { AccountID: "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7", Balance: int64(1000000000000000000), SequenceNumber: 0, - SequenceTime: 0, MasterWeight: 1, }, }).Return(nil).Once() diff --git a/services/horizon/internal/ingest/processors/accounts_processor.go b/services/horizon/internal/ingest/processors/accounts_processor.go index 8386fdbab7..8130175ab6 100644 --- a/services/horizon/internal/ingest/processors/accounts_processor.go +++ b/services/horizon/internal/ingest/processors/accounts_processor.go @@ -3,6 +3,7 @@ package processors import ( "context" + "github.com/guregu/null/zero" "github.com/stellar/go/ingest" "github.com/stellar/go/services/horizon/internal/db2/history" "github.com/stellar/go/support/errors" @@ -117,8 +118,8 @@ func (p *AccountsProcessor) ledgerEntryToRow(entry xdr.LedgerEntry) history.Acco BuyingLiabilities: int64(liabilities.Buying), SellingLiabilities: int64(liabilities.Selling), SequenceNumber: int64(account.SeqNum), - SequenceLedger: uint32(account.SeqLedger()), - SequenceTime: uint64(account.SeqTime()), + SequenceLedger: zero.IntFrom(int64(account.SeqLedger())), + SequenceTime: zero.IntFrom(int64(account.SeqTime())), NumSubEntries: uint32(account.NumSubEntries), InflationDestination: inflationDestination, Flags: uint32(account.Flags), diff --git a/services/horizon/internal/ingest/processors/accounts_processor_test.go b/services/horizon/internal/ingest/processors/accounts_processor_test.go index 51c3c8e9ae..9b9c98d7b5 100644 --- a/services/horizon/internal/ingest/processors/accounts_processor_test.go +++ b/services/horizon/internal/ingest/processors/accounts_processor_test.go @@ -6,6 +6,7 @@ import ( "context" "testing" + "github.com/guregu/null/zero" "github.com/stellar/go/ingest" "github.com/stellar/go/services/horizon/internal/db2/history" "github.com/stellar/go/xdr" @@ -47,7 +48,6 @@ func (s *AccountsProcessorTestSuiteState) TestCreatesAccounts() { { LastModifiedLedger: 123, AccountID: "GC3C4AKRBQLHOJ45U4XG35ESVWRDECWO5XLDGYADO6DPR3L7KIDVUMML", - SequenceTime: 0, MasterWeight: 1, ThresholdLow: 1, ThresholdMedium: 1, @@ -152,7 +152,6 @@ func (s *AccountsProcessorTestSuiteLedger) TestNewAccount() { []history.AccountEntry{ { AccountID: "GC3C4AKRBQLHOJ45U4XG35ESVWRDECWO5XLDGYADO6DPR3L7KIDVUMML", - SequenceTime: 0, MasterWeight: 0, ThresholdLow: 1, ThresholdMedium: 2, @@ -164,7 +163,7 @@ func (s *AccountsProcessorTestSuiteLedger) TestNewAccount() { ).Return(nil).Once() } -func (s *AccountsProcessorTestSuiteLedger) TestNewAccountWithExtension() { +func (s *AccountsProcessorTestSuiteLedger) TestNewAccountUpgrade() { account := xdr.AccountEntry{ AccountId: xdr.MustAddress("GC3C4AKRBQLHOJ45U4XG35ESVWRDECWO5XLDGYADO6DPR3L7KIDVUMML"), Thresholds: [4]byte{1, 1, 1, 1}, @@ -172,16 +171,8 @@ func (s *AccountsProcessorTestSuiteLedger) TestNewAccountWithExtension() { V: 1, V1: &xdr.AccountEntryExtensionV1{ Ext: xdr.AccountEntryExtensionV1Ext{ - V: 2, - V2: &xdr.AccountEntryExtensionV2{ - Ext: xdr.AccountEntryExtensionV2Ext{ - V: 3, - V3: &xdr.AccountEntryExtensionV3{ - SeqLedger: 2345, - SeqTime: 1647265533, - }, - }, - }, + V: 2, + V2: &xdr.AccountEntryExtensionV2{}, }, }, }, @@ -250,8 +241,8 @@ func (s *AccountsProcessorTestSuiteLedger) TestNewAccountWithExtension() { []history.AccountEntry{ { AccountID: "GC3C4AKRBQLHOJ45U4XG35ESVWRDECWO5XLDGYADO6DPR3L7KIDVUMML", - SequenceLedger: 2346, - SequenceTime: 1647265534, + SequenceLedger: zero.IntFrom(2346), + SequenceTime: zero.IntFrom(1647265534), MasterWeight: 0, ThresholdLow: 1, ThresholdMedium: 2, @@ -338,8 +329,8 @@ func (s *AccountsProcessorTestSuiteLedger) TestProcessUpgradeChange() { { LastModifiedLedger: uint32(lastModifiedLedgerSeq) + 1, AccountID: "GC3C4AKRBQLHOJ45U4XG35ESVWRDECWO5XLDGYADO6DPR3L7KIDVUMML", - SequenceTime: 0, - SequenceLedger: 0, + SequenceTime: zero.IntFrom(0), + SequenceLedger: zero.IntFrom(0), MasterWeight: 0, ThresholdLow: 1, ThresholdMedium: 2, @@ -405,8 +396,6 @@ func (s *AccountsProcessorTestSuiteLedger) TestFeeProcessedBeforeEverythingElse( LastModifiedLedger: 0, AccountID: "GAHK7EEG2WWHVKDNT4CEQFZGKF2LGDSW2IVM4S5DP42RBW3K6BTODB4A", Balance: 300, - SequenceTime: 0, - SequenceLedger: 0, }, }, ).Return(nil).Once() diff --git a/services/horizon/internal/ingest/verify.go b/services/horizon/internal/ingest/verify.go index 99d7b7a265..ff8d047252 100644 --- a/services/horizon/internal/ingest/verify.go +++ b/services/horizon/internal/ingest/verify.go @@ -394,6 +394,18 @@ func addAccountsToStateVerifier(ctx context.Context, verifier *verify.StateVerif } } + // Accounts that haven't done anything since Protocol 19 will not have a + // V3 extension, so we need to check whether or not this extension needs + // to be filled out. + v3extension := xdr.AccountEntryExtensionV2Ext{V: 0} + if row.SequenceLedger.Valid && row.SequenceTime.Valid { + v3extension.V = 3 + v3extension.V3 = &xdr.AccountEntryExtensionV3{ + SeqLedger: xdr.Uint32(row.SequenceLedger.Int64), + SeqTime: xdr.TimePoint(row.SequenceTime.Int64), + } + } + account := &xdr.AccountEntry{ AccountId: xdr.MustAddress(row.AccountID), Balance: xdr.Int64(row.Balance), @@ -422,13 +434,7 @@ func addAccountsToStateVerifier(ctx context.Context, verifier *verify.StateVerif NumSponsored: xdr.Uint32(row.NumSponsored), NumSponsoring: xdr.Uint32(row.NumSponsoring), SignerSponsoringIDs: signerSponsoringIDs, - Ext: xdr.AccountEntryExtensionV2Ext{ - V: 3, - V3: &xdr.AccountEntryExtensionV3{ - SeqLedger: xdr.Uint32(row.SequenceLedger), - SeqTime: xdr.TimePoint(row.SequenceTime), - }, - }, + Ext: v3extension, }, }, }, diff --git a/services/horizon/internal/ingest/verify_range_state_test.go b/services/horizon/internal/ingest/verify_range_state_test.go index 4ca0efda2c..49a4e4175d 100644 --- a/services/horizon/internal/ingest/verify_range_state_test.go +++ b/services/horizon/internal/ingest/verify_range_state_test.go @@ -7,9 +7,11 @@ import ( "database/sql" "fmt" "io" + "math" "testing" "github.com/guregu/null" + "github.com/guregu/null/zero" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" @@ -334,7 +336,7 @@ func (s *VerifyRangeStateTestSuite) TestSuccessWithVerify() { Ext: xdr.AccountEntryExtensionV2Ext{ V: 3, V3: &xdr.AccountEntryExtensionV3{ - SeqTime: xdr.TimePoint(18446744011573954816), + SeqTime: xdr.TimePoint(math.MaxInt64), SeqLedger: xdr.Uint32(12345678), }, }, @@ -485,8 +487,8 @@ func (s *VerifyRangeStateTestSuite) TestSuccessWithVerify() { AccountID: mockAccountID, Balance: 600, LastModifiedLedger: 62, - SequenceTime: 18446744011573954816, - SequenceLedger: 12345678, + SequenceTime: zero.IntFrom(9223372036854775807), + SequenceLedger: zero.IntFrom(12345678), MasterWeight: 1, NumSponsored: 0, NumSponsoring: 2, diff --git a/services/horizon/internal/integration/protocol_19_upgrade_test.go b/services/horizon/internal/integration/protocol_19_upgrade_test.go new file mode 100644 index 0000000000..1205260f59 --- /dev/null +++ b/services/horizon/internal/integration/protocol_19_upgrade_test.go @@ -0,0 +1,104 @@ +package integration + +import ( + "strconv" + "testing" + + "github.com/stellar/go/clients/horizonclient" + "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/services/horizon/internal/test/integration" + "github.com/stellar/go/txnbuild" + "github.com/stretchr/testify/assert" +) + +// TestProtocol19Upgrade tests that crossing the upgrade boundary results in the +// correct behavior and no crashes. +func TestProtocol19Upgrade(t *testing.T) { + itest := integration.NewTest(t, integration.Config{ProtocolVersion: 18}) + + master := itest.Master() + masterAccount := itest.MasterAccount() + + if integration.GetCoreMaxSupportedProtocol() < 19 { + t.Skip("This test run does not support Protocol 19") + } + + // Note: These tests are combined to avoid the extra setup/teardown. + + // TestTransactionPreconditionsPremature ensures that submitting + // transactions that use Protocol 19 features fail correctly. + t.Run("TestTransactionPreconditionsPremature", func(t *testing.T) { + tt := assert.New(t) + + // Submit a transaction with extra preconditions set too early. + txParams := txnbuild.TransactionParams{ + BaseFee: txnbuild.MinBaseFee, + SourceAccount: masterAccount, + IncrementSequenceNum: true, + // Phony operation to run + Operations: []txnbuild.Operation{ + &txnbuild.Payment{ + Destination: masterAccount.GetAccountID(), + Amount: "10", + Asset: txnbuild.NativeAsset{}, + }, + }, + Preconditions: txnbuild.Preconditions{ + TimeBounds: txnbuild.NewInfiniteTimeout(), + LedgerBounds: &txnbuild.LedgerBounds{0, 100}, + }, + } + _, err := itest.SubmitTransaction(master, txParams) + + tt.Error(err) + if prob := horizonclient.GetError(err); prob != nil { + if results, ok := prob.Problem.Extras["result_codes"].(map[string]interface{}); ok { + tt.Equal("tx_not_supported", results["transaction"]) + } else { + tt.FailNow("result_codes couldn't be parsed: %+v", results) + } + } else { + tt.Error(prob) + } + }) + + // TestTransactionAccountV3Upgrade ensures that upgrading over the + // Protocol 19 boundary correctly adds the V3 fields. + t.Run("TestTransactionAccountV3Upgrade", func(t *testing.T) { + var account horizon.Account + tt := assert.New(t) + + // Submit phony operation which should bump the sequence number but not + // actually track it in the extension. + tx := submitPhonyOp(itest) + account = itest.MasterAccountDetails() + + // Check that the account response has V3 fields omitted. + tt.EqualValues(0, account.SequenceLedger) + tt.Equal("", account.SequenceTime) + + itest.UpgradeProtocol(19) + + // Submit phony operation which should trigger the new fields. + tx = submitPhonyOp(itest) + + // Refresh master account and check that the account response has the new + // AccountV3 fields + account = itest.MasterAccountDetails() + tt.Equal(uint32(tx.Ledger), account.SequenceLedger) + tt.Equal(strconv.FormatInt(tx.LedgerCloseTime.Unix(), 10), account.SequenceTime) + }) +} + +func submitPhonyOp(itest *integration.Test) horizon.Transaction { + master := itest.Master() + account := itest.MasterAccount() + + return itest.MustSubmitOperations(account, master, + &txnbuild.Payment{ + Destination: master.Address(), + Amount: "10", + Asset: txnbuild.NativeAsset{}, + }, + ) +} diff --git a/services/horizon/internal/integration/transaction_preconditions_test.go b/services/horizon/internal/integration/transaction_preconditions_test.go index ea50e15f42..13f29c59d6 100644 --- a/services/horizon/internal/integration/transaction_preconditions_test.go +++ b/services/horizon/internal/integration/transaction_preconditions_test.go @@ -3,7 +3,7 @@ package integration import ( "bytes" "encoding/base64" - "fmt" + "math" "strconv" "sync" "testing" @@ -211,6 +211,8 @@ func TestTransactionPreconditionsMinSequenceNumberAge(t *testing.T) { if itest.GetEffectiveProtocolVersion() < 19 { t.Skip("Can't run with protocol < 19") } + submitPhonyOp(itest) // upgrades master account to v3 + master := itest.Master() masterAccount := itest.MasterAccount() currentAccountSeq, err := masterAccount.GetSequenceNumber() @@ -228,28 +230,34 @@ func TestTransactionPreconditionsMinSequenceNumberAge(t *testing.T) { tt.GreaterOrEqual(signedAcctSeqTime, int64(0)) acctSeqTime := uint64(signedAcctSeqTime) networkSeqTime := uint64(ledgers.Embedded.Records[0].ClosedAt.UTC().Unix()) + tt.GreaterOrEqual(networkSeqTime, acctSeqTime) // build a tx with seqnum based on master.seqNum+1 as source account txParams := buildTXParams(master, masterAccount, currentAccountSeq+1) - // this txsub will error because the tx preconditions require a min sequence age - // which has been set 10000 seconds greater than the current difference between - // network ledger sequence time and account sequnece time + // This txsub will error because the tx preconditions require a min sequence + // age which has been set 10000 seconds greater than the current difference + // between network ledger sequence time and account sequnece time. txParams.Preconditions.MinSequenceNumberAge = networkSeqTime - acctSeqTime + 10000 - _, err = itest.SubmitMultiSigTransaction([]*keypair.Full{master}, txParams) + tx, err := itest.SubmitMultiSigTransaction([]*keypair.Full{master}, txParams) tt.Error(err) - txParams.Preconditions.MinSequenceNumberAge = networkSeqTime - acctSeqTime - 1 - // Now the transaction should be submitted without problems, the min sequence age - // is set to be one second less then the current difference between network time and account sequence time. - tx, err := itest.SubmitMultiSigTransaction([]*keypair.Full{master}, txParams) - tt.NoError(err) + // Now the transaction should be submitted without problems, the min + // sequence age is set to be 1s more than the current difference between + // network time and account sequence time. + time.Sleep(time.Second) + txParams.Preconditions.MinSequenceNumberAge = 1 + tx, err = itest.SubmitMultiSigTransaction([]*keypair.Full{master}, txParams) + itest.LogFailedTx(tx, err) //verify roundtrip to network and back through the horizon api returns same precondition values txHistory, err := itest.Client().TransactionDetail(tx.Hash) - assert.NoError(t, err) - assert.EqualValues(t, txHistory.Preconditions.MinAccountSequenceAge, - fmt.Sprint(uint64(txParams.Preconditions.MinSequenceNumberAge))) + tt.NoError(err) + + expected := txParams.Preconditions.MinSequenceNumberAge + actual, err := strconv.ParseUint(txHistory.Preconditions.MinAccountSequenceAge, 10, 64) + tt.NoError(err) + tt.Equal(expected, actual) } func TestTransactionPreconditionsMinSequenceNumberLedgerGap(t *testing.T) { @@ -289,55 +297,6 @@ func TestTransactionPreconditionsMinSequenceNumberLedgerGap(t *testing.T) { assert.Equal(t, txHistory.Preconditions.MinAccountSequenceLedgerGap, txParams.Preconditions.MinSequenceNumberLedgerGap) } -func buildTXParams(master *keypair.Full, masterAccount txnbuild.Account, txSequence int64) txnbuild.TransactionParams { - return txnbuild.TransactionParams{ - SourceAccount: &txnbuild.SimpleAccount{ - AccountID: masterAccount.GetAccountID(), - Sequence: txSequence, - }, - // Phony operation to run - Operations: []txnbuild.Operation{ - &txnbuild.Payment{ - Destination: master.Address(), - Amount: "10", - Asset: txnbuild.NativeAsset{}, - }, - }, - BaseFee: txnbuild.MinBaseFee, - Memo: nil, - Preconditions: txnbuild.Preconditions{ - TimeBounds: txnbuild.NewInfiniteTimeout(), - }, - } -} - -func TestTransactionPreconditionsAccountV3Fields(t *testing.T) { - tt := assert.New(t) - itest := integration.NewTest(t, integration.Config{}) - if itest.GetEffectiveProtocolVersion() < 19 { - t.Skip("Can't run with protocol < 19") - } - master := itest.Master() - masterAccount := itest.MasterAccount() - - // Submit phony operation - tx := itest.MustSubmitOperations(masterAccount, master, - &txnbuild.Payment{ - Destination: master.Address(), - Amount: "10", - Asset: txnbuild.NativeAsset{}, - }, - ) - - // refresh master account - account, err := itest.Client().AccountDetail(sdk.AccountRequest{AccountID: master.Address()}) - assert.NoError(t, err) - - // Check that the account response has the new AccountV3 fields - tt.Equal(uint32(tx.Ledger), account.SequenceLedger) - tt.Equal(strconv.FormatInt(tx.LedgerCloseTime.Unix(), 10), account.SequenceTime) -} - // TestTransactionWithoutPreconditions ensures that Horizon doesn't break when // we have a PRECOND_NONE type transaction (which is not possible to submit // through SDKs, but is absolutely still possible). @@ -398,15 +357,69 @@ func TestTransactionWithoutPreconditions(t *testing.T) { txResp, err := itest.Client().SubmitTransactionXDR(b64) tt.NoError(err) - fmt.Println( - "envelopeXDR", txResp.EnvelopeXdr, - "resultXDR", txResp.ResultXdr, - // "feeChangesXDR", txResp.feeChangesXDR, - "metaXDR", txResp.FeeMetaXdr, - "hash", txResp.Hash, - ) - txResp2, err := itest.Client().TransactionDetail(txResp.Hash) tt.NoError(err) tt.Nil(txResp2.Preconditions) } + +func TestTransactionPreconditionsEdgeCases(t *testing.T) { + tt := assert.New(t) + itest := integration.NewTest(t, integration.Config{}) + if itest.GetEffectiveProtocolVersion() < 19 { + t.Skip("Can't run with protocol < 19") + } + master := itest.Master() + masterAccount := itest.MasterAccount() + + maxMinSeq := int64(math.MaxInt64) + preconditionTests := []txnbuild.Preconditions{ + {LedgerBounds: &txnbuild.LedgerBounds{1, 0}}, + {LedgerBounds: &txnbuild.LedgerBounds{0, math.MaxUint32}}, + {LedgerBounds: &txnbuild.LedgerBounds{math.MaxUint32, 1}}, + { + LedgerBounds: &txnbuild.LedgerBounds{math.MaxUint32, 1}, + ExtraSigners: []string{}, + }, + { + MinSequenceNumber: &maxMinSeq, + MinSequenceNumberLedgerGap: math.MaxUint32, + MinSequenceNumberAge: math.MaxUint64, + ExtraSigners: nil, + }, + } + + for _, precondition := range preconditionTests { + seqNum, err := masterAccount.IncrementSequenceNumber() + tt.NoError(err) + + params := buildTXParams(master, masterAccount, seqNum) + precondition.TimeBounds = txnbuild.NewInfiniteTimeout() + params.Preconditions = precondition + + // The goal here is not to check for validation or errors or responses, + // but rather to just make sure the edge case doesn't crash Horizon. + itest.SubmitTransaction(master, params) + } +} + +func buildTXParams(master *keypair.Full, masterAccount txnbuild.Account, txSequence int64) txnbuild.TransactionParams { + return txnbuild.TransactionParams{ + SourceAccount: &txnbuild.SimpleAccount{ + AccountID: masterAccount.GetAccountID(), + Sequence: txSequence, + }, + // Phony operation to run + Operations: []txnbuild.Operation{ + &txnbuild.Payment{ + Destination: master.Address(), + Amount: "10", + Asset: txnbuild.NativeAsset{}, + }, + }, + BaseFee: txnbuild.MinBaseFee, + Memo: nil, + Preconditions: txnbuild.Preconditions{ + TimeBounds: txnbuild.NewInfiniteTimeout(), + }, + } +} diff --git a/services/horizon/internal/resourceadapter/account_entry.go b/services/horizon/internal/resourceadapter/account_entry.go index 7c38c3e9e2..b0d891d851 100644 --- a/services/horizon/internal/resourceadapter/account_entry.go +++ b/services/horizon/internal/resourceadapter/account_entry.go @@ -27,8 +27,11 @@ func PopulateAccountEntry( dest.PT = account.AccountID dest.AccountID = account.AccountID dest.Sequence = strconv.FormatInt(account.SequenceNumber, 10) - dest.SequenceLedger = account.SequenceLedger - dest.SequenceTime = fmt.Sprintf("%d", account.SequenceTime) + if account.SequenceLedger.Valid && account.SequenceTime.Valid { + dest.SequenceLedger = uint32(account.SequenceLedger.Int64) + dest.SequenceTime = fmt.Sprintf("%d", account.SequenceTime.Int64) + } + dest.SubentryCount = int32(account.NumSubEntries) dest.InflationDestination = account.InflationDestination dest.HomeDomain = account.HomeDomain diff --git a/services/horizon/internal/resourceadapter/account_entry_test.go b/services/horizon/internal/resourceadapter/account_entry_test.go index 33c3f613ef..73dfd4ebd0 100644 --- a/services/horizon/internal/resourceadapter/account_entry_test.go +++ b/services/horizon/internal/resourceadapter/account_entry_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/guregu/null" + "github.com/guregu/null/zero" "github.com/stellar/go/amount" . "github.com/stellar/go/protocols/horizon" @@ -45,8 +46,8 @@ var ( AccountID: accountID.Address(), Balance: 20000, SequenceNumber: 223456789, - SequenceLedger: 2345, - SequenceTime: 1647265533, + SequenceLedger: zero.IntFrom(2345), + SequenceTime: zero.IntFrom(1647265533), NumSubEntries: 10, InflationDestination: inflationDest.Address(), Flags: 0b1001, // required and clawback @@ -146,8 +147,8 @@ func TestPopulateAccountEntry(t *testing.T) { tt.Equal(account.AccountID, hAccount.AccountID) tt.Equal(account.AccountID, hAccount.PT) tt.Equal(strconv.FormatInt(account.SequenceNumber, 10), hAccount.Sequence) - tt.Equal(account.SequenceLedger, hAccount.SequenceLedger) - tt.Equal(fmt.Sprintf("%d", account.SequenceTime), hAccount.SequenceTime) + tt.Equal(uint32(account.SequenceLedger.Int64), hAccount.SequenceLedger) + tt.Equal(fmt.Sprintf("%d", account.SequenceTime.Int64), hAccount.SequenceTime) tt.Equal(account.NumSubEntries, uint32(hAccount.SubentryCount)) tt.Equal(account.InflationDestination, hAccount.InflationDestination) tt.Equal(account.HomeDomain, hAccount.HomeDomain) diff --git a/services/horizon/internal/test/integration/integration.go b/services/horizon/internal/test/integration/integration.go index 3594c36401..2ec19226e2 100644 --- a/services/horizon/internal/test/integration/integration.go +++ b/services/horizon/internal/test/integration/integration.go @@ -120,7 +120,7 @@ func NewTest(t *testing.T, config Config) *Test { config.ProtocolVersion = ingest.MaxSupportedProtocolVersion // If the environment tells us that Core only supports up to certain version, // use that. - maxSupportedCoreProtocolFromEnv := getCoreMaxSupportedProtocol() + maxSupportedCoreProtocolFromEnv := GetCoreMaxSupportedProtocol() if maxSupportedCoreProtocolFromEnv != 0 && maxSupportedCoreProtocolFromEnv < ingest.MaxSupportedProtocolVersion { config.ProtocolVersion = maxSupportedCoreProtocolFromEnv } @@ -468,7 +468,8 @@ func (i *Test) WaitForHorizon() { } if uint32(root.CurrentProtocolVersion) == i.config.ProtocolVersion { - i.t.Logf("Horizon protocol version matches... %v", root) + i.t.Logf("Horizon protocol version matches %d: %+v", + root.CurrentProtocolVersion, root) return } } @@ -516,13 +517,14 @@ func (i *Test) Master() *keypair.Full { } func (i *Test) MasterAccount() txnbuild.Account { - master, client := i.Master(), i.Client() - request := sdk.AccountRequest{AccountID: master.Address()} - account, err := client.AccountDetail(request) - panicIf(err) + account := i.MasterAccountDetails() return &account } +func (i *Test) MasterAccountDetails() proto.Account { + return i.MustGetAccount(i.Master()) +} + func (i *Test) CurrentTest() *testing.T { return i.t } @@ -785,7 +787,7 @@ func (i *Test) LogFailedTx(txResponse proto.Transaction, horizonResult error) { err := xdr.SafeUnmarshalBase64(txResponse.ResultXdr, &txResult) assert.NoErrorf(t, err, "Unmarshalling transaction failed.") assert.Equalf(t, xdr.TransactionResultCodeTxSuccess, txResult.Result.Code, - "Transaction doesn't have success code.") + "Transaction did not succeed: %d", txResult.Result.Code) } func (i *Test) GetPassPhrase() string { @@ -874,7 +876,7 @@ func mapToFlags(params map[string]string) []string { return args } -func getCoreMaxSupportedProtocol() uint32 { +func GetCoreMaxSupportedProtocol() uint32 { str := os.Getenv("HORIZON_INTEGRATION_TESTS_CORE_MAX_SUPPORTED_PROTOCOL") if str == "" { return 0 diff --git a/xdr/Stellar-ledger-entries.x b/xdr/Stellar-ledger-entries.x index e0f719d0f1..3eb578f16b 100644 --- a/xdr/Stellar-ledger-entries.x +++ b/xdr/Stellar-ledger-entries.x @@ -306,7 +306,8 @@ struct TrustLineEntry enum OfferEntryFlags { - // an offer with this flag will not act on and take a reverse offer of equal price + // an offer with this flag will not act on and take a reverse offer of equal + // price PASSIVE_FLAG = 1 }; @@ -387,7 +388,7 @@ case CLAIM_PREDICATE_BEFORE_ABSOLUTE_TIME: int64 absBefore; // Predicate will be true if closeTime < absBefore case CLAIM_PREDICATE_BEFORE_RELATIVE_TIME: int64 relBefore; // Seconds since closeTime of the ledger in which the - // ClaimableBalanceEntry was created + // ClaimableBalanceEntry was created }; enum ClaimantType @@ -466,7 +467,7 @@ struct LiquidityPoolConstantProductParameters { Asset assetA; // assetA < assetB Asset assetB; - int32 fee; // Fee is in basis points, so the actual rate is (fee/100)% + int32 fee; // Fee is in basis points, so the actual rate is (fee/100)% }; struct LiquidityPoolEntry @@ -483,7 +484,8 @@ struct LiquidityPoolEntry int64 reserveA; // amount of A in the pool int64 reserveB; // amount of B in the pool int64 totalPoolShares; // total number of pool shares issued - int64 poolSharesTrustLineCount; // number of trust lines for the associated pool shares + int64 poolSharesTrustLineCount; // number of trust lines for the + // associated pool shares } constantProduct; } body; diff --git a/xdr/Stellar-transaction.x b/xdr/Stellar-transaction.x index a9fdbe69f1..f2f593c213 100644 --- a/xdr/Stellar-transaction.x +++ b/xdr/Stellar-transaction.x @@ -445,10 +445,10 @@ const LIQUIDITY_POOL_FEE_V18 = 30; struct LiquidityPoolDepositOp { PoolID liquidityPoolID; - int64 maxAmountA; // maximum amount of first asset to deposit - int64 maxAmountB; // maximum amount of second asset to deposit - Price minPrice; // minimum depositA/depositB - Price maxPrice; // maximum depositA/depositB + int64 maxAmountA; // maximum amount of first asset to deposit + int64 maxAmountB; // maximum amount of second asset to deposit + Price minPrice; // minimum depositA/depositB + Price maxPrice; // maximum depositA/depositB }; /* Withdraw assets from a liquidity pool @@ -460,9 +460,9 @@ struct LiquidityPoolDepositOp struct LiquidityPoolWithdrawOp { PoolID liquidityPoolID; - int64 amount; // amount of pool shares to withdraw - int64 minAmountA; // minimum amount of first asset to withdraw - int64 minAmountB; // minimum amount of second asset to withdraw + int64 amount; // amount of pool shares to withdraw + int64 minAmountA; // minimum amount of first asset to withdraw + int64 minAmountB; // minimum amount of second asset to withdraw }; /* An operation is the lowest unit of work that a transaction does */ @@ -582,13 +582,14 @@ struct LedgerBounds uint32 maxLedger; // 0 here means no maxLedger }; -struct PreconditionsV2 { - TimeBounds *timeBounds; +struct PreconditionsV2 +{ + TimeBounds* timeBounds; // Transaction only valid for ledger numbers n such that // minLedger <= n < maxLedger (if maxLedger == 0, then // only minLedger is checked) - LedgerBounds *ledgerBounds; + LedgerBounds* ledgerBounds; // If NULL, only valid when sourceAccount's sequence number // is seqNum - 1. Otherwise, valid when sourceAccount's @@ -596,7 +597,7 @@ struct PreconditionsV2 { // Note that after execution the account's sequence number // is always raised to tx.seqNum, and a transaction is not // valid if tx.seqNum is too high to ensure replay protection. - SequenceNumber *minSeqNum; + SequenceNumber* minSeqNum; // For the transaction to be valid, the current ledger time must // be at least minSeqAge greater than sourceAccount's seqTime. @@ -614,19 +615,21 @@ struct PreconditionsV2 { SignerKey extraSigners<2>; }; -enum PreconditionType { +enum PreconditionType +{ PRECOND_NONE = 0, PRECOND_TIME = 1, PRECOND_V2 = 2 }; -union Preconditions switch (PreconditionType type) { - case PRECOND_NONE: - void; - case PRECOND_TIME: - TimeBounds timeBounds; - case PRECOND_V2: - PreconditionsV2 v2; +union Preconditions switch (PreconditionType type) +{ +case PRECOND_NONE: + void; +case PRECOND_TIME: + TimeBounds timeBounds; +case PRECOND_V2: + PreconditionsV2 v2; }; // maximum number of operations per transaction @@ -1107,10 +1110,12 @@ enum ChangeTrustResultCode // cannot create with a limit of 0 CHANGE_TRUST_LOW_RESERVE = -4, // not enough funds to create a new trust line, - CHANGE_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed + CHANGE_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed CHANGE_TRUST_TRUST_LINE_MISSING = -6, // Asset trustline is missing for pool - CHANGE_TRUST_CANNOT_DELETE = -7, // Asset trustline is still referenced in a pool - CHANGE_TRUST_NOT_AUTH_MAINTAIN_LIABILITIES = -8 // Asset trustline is deauthorized + CHANGE_TRUST_CANNOT_DELETE = + -7, // Asset trustline is still referenced in a pool + CHANGE_TRUST_NOT_AUTH_MAINTAIN_LIABILITIES = + -8 // Asset trustline is deauthorized }; union ChangeTrustResult switch (ChangeTrustResultCode code) @@ -1132,10 +1137,10 @@ enum AllowTrustResultCode ALLOW_TRUST_NO_TRUST_LINE = -2, // trustor does not have a trustline // source account does not require trust ALLOW_TRUST_TRUST_NOT_REQUIRED = -3, - ALLOW_TRUST_CANT_REVOKE = -4, // source account can't revoke trust, + ALLOW_TRUST_CANT_REVOKE = -4, // source account can't revoke trust, ALLOW_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed - ALLOW_TRUST_LOW_RESERVE = -6 // claimable balances can't be created - // on revoke due to low reserves + ALLOW_TRUST_LOW_RESERVE = -6 // claimable balances can't be created + // on revoke due to low reserves }; union AllowTrustResult switch (AllowTrustResultCode code) @@ -1432,8 +1437,7 @@ enum LiquidityPoolDepositResultCode LIQUIDITY_POOL_DEPOSIT_POOL_FULL = -7 // pool reserves are full }; -union LiquidityPoolDepositResult switch ( - LiquidityPoolDepositResultCode code) +union LiquidityPoolDepositResult switch (LiquidityPoolDepositResultCode code) { case LIQUIDITY_POOL_DEPOSIT_SUCCESS: void; @@ -1449,18 +1453,17 @@ enum LiquidityPoolWithdrawResultCode LIQUIDITY_POOL_WITHDRAW_SUCCESS = 0, // codes considered as "failure" for the operation - LIQUIDITY_POOL_WITHDRAW_MALFORMED = -1, // bad input - LIQUIDITY_POOL_WITHDRAW_NO_TRUST = -2, // no trust line for one of the - // assets - LIQUIDITY_POOL_WITHDRAW_UNDERFUNDED = -3, // not enough balance of the - // pool share - LIQUIDITY_POOL_WITHDRAW_LINE_FULL = -4, // would go above limit for one - // of the assets - LIQUIDITY_POOL_WITHDRAW_UNDER_MINIMUM = -5 // didn't withdraw enough + LIQUIDITY_POOL_WITHDRAW_MALFORMED = -1, // bad input + LIQUIDITY_POOL_WITHDRAW_NO_TRUST = -2, // no trust line for one of the + // assets + LIQUIDITY_POOL_WITHDRAW_UNDERFUNDED = -3, // not enough balance of the + // pool share + LIQUIDITY_POOL_WITHDRAW_LINE_FULL = -4, // would go above limit for one + // of the assets + LIQUIDITY_POOL_WITHDRAW_UNDER_MINIMUM = -5 // didn't withdraw enough }; -union LiquidityPoolWithdrawResult switch ( - LiquidityPoolWithdrawResultCode code) +union LiquidityPoolWithdrawResult switch (LiquidityPoolWithdrawResultCode code) { case LIQUIDITY_POOL_WITHDRAW_SUCCESS: void; @@ -1562,7 +1565,9 @@ enum TransactionResultCode txNOT_SUPPORTED = -12, // transaction type not supported txFEE_BUMP_INNER_FAILED = -13, // fee bump inner transaction failed txBAD_SPONSORSHIP = -14, // sponsorship not confirmed - txBAD_MIN_SEQ_AGE_OR_GAP = -15 //minSeqAge or minSeqLedgerGap conditions not met + txBAD_MIN_SEQ_AGE_OR_GAP = + -15, // minSeqAge or minSeqLedgerGap conditions not met + txMALFORMED = -16 // precondition is invalid }; // InnerTransactionResult must be binary compatible with TransactionResult @@ -1592,6 +1597,7 @@ struct InnerTransactionResult // txFEE_BUMP_INNER_FAILED is not included case txBAD_SPONSORSHIP: case txBAD_MIN_SEQ_AGE_OR_GAP: + case txMALFORMED: void; } result; diff --git a/xdr/Stellar-types.x b/xdr/Stellar-types.x index 562f8fc269..c3a1ebe2c8 100644 --- a/xdr/Stellar-types.x +++ b/xdr/Stellar-types.x @@ -17,9 +17,10 @@ typedef hyper int64; // An ExtensionPoint is always marshaled as a 32-bit 0 value. At a // later point, it can be replaced by a different union so as to // extend a structure. -union ExtensionPoint switch (int v) { +union ExtensionPoint switch (int v) +{ case 0: - void; + void; }; enum CryptoKeyType @@ -63,7 +64,8 @@ case SIGNER_KEY_TYPE_HASH_X: /* Hash of random 256 bit preimage X */ uint256 hashX; case SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD: - struct { + struct + { /* Public key that must sign the payload. */ uint256 ed25519; /* Payload to be raw signed by ed25519. */ diff --git a/xdr/xdr_generated.go b/xdr/xdr_generated.go index f21480c2c6..ddae1f9b30 100644 --- a/xdr/xdr_generated.go +++ b/xdr/xdr_generated.go @@ -5227,7 +5227,8 @@ var _ xdrType = (*TrustLineEntry)(nil) // // enum OfferEntryFlags // { -// // an offer with this flag will not act on and take a reverse offer of equal price +// // an offer with this flag will not act on and take a reverse offer of equal +// // price // PASSIVE_FLAG = 1 // }; // @@ -5861,7 +5862,7 @@ var _ xdrType = (*ClaimPredicateType)(nil) // int64 absBefore; // Predicate will be true if closeTime < absBefore // case CLAIM_PREDICATE_BEFORE_RELATIVE_TIME: // int64 relBefore; // Seconds since closeTime of the ledger in which the -// // ClaimableBalanceEntry was created +// // ClaimableBalanceEntry was created // }; // type ClaimPredicate struct { @@ -7313,7 +7314,7 @@ var _ xdrType = (*ClaimableBalanceEntry)(nil) // { // Asset assetA; // assetA < assetB // Asset assetB; -// int32 fee; // Fee is in basis points, so the actual rate is (fee/100)% +// int32 fee; // Fee is in basis points, so the actual rate is (fee/100)% // }; // type LiquidityPoolConstantProductParameters struct { @@ -7397,7 +7398,8 @@ var _ xdrType = (*LiquidityPoolConstantProductParameters)(nil) // int64 reserveA; // amount of A in the pool // int64 reserveB; // amount of B in the pool // int64 totalPoolShares; // total number of pool shares issued -// int64 poolSharesTrustLineCount; // number of trust lines for the associated pool shares +// int64 poolSharesTrustLineCount; // number of trust lines for the +// // associated pool shares // } // type LiquidityPoolEntryConstantProduct struct { @@ -7502,7 +7504,8 @@ var _ xdrType = (*LiquidityPoolEntryConstantProduct)(nil) // int64 reserveA; // amount of A in the pool // int64 reserveB; // amount of B in the pool // int64 totalPoolShares; // total number of pool shares issued -// int64 poolSharesTrustLineCount; // number of trust lines for the associated pool shares +// int64 poolSharesTrustLineCount; // number of trust lines for the +// // associated pool shares // } constantProduct; // } // @@ -7650,7 +7653,8 @@ var _ xdrType = (*LiquidityPoolEntryBody)(nil) // int64 reserveA; // amount of A in the pool // int64 reserveB; // amount of B in the pool // int64 totalPoolShares; // total number of pool shares issued -// int64 poolSharesTrustLineCount; // number of trust lines for the associated pool shares +// int64 poolSharesTrustLineCount; // number of trust lines for the +// // associated pool shares // } constantProduct; // } // body; @@ -20204,10 +20208,10 @@ const LiquidityPoolFeeV18 = 30 // struct LiquidityPoolDepositOp // { // PoolID liquidityPoolID; -// int64 maxAmountA; // maximum amount of first asset to deposit -// int64 maxAmountB; // maximum amount of second asset to deposit -// Price minPrice; // minimum depositA/depositB -// Price maxPrice; // maximum depositA/depositB +// int64 maxAmountA; // maximum amount of first asset to deposit +// int64 maxAmountB; // maximum amount of second asset to deposit +// Price minPrice; // minimum depositA/depositB +// Price maxPrice; // maximum depositA/depositB // }; // type LiquidityPoolDepositOp struct { @@ -20305,9 +20309,9 @@ var _ xdrType = (*LiquidityPoolDepositOp)(nil) // struct LiquidityPoolWithdrawOp // { // PoolID liquidityPoolID; -// int64 amount; // amount of pool shares to withdraw -// int64 minAmountA; // minimum amount of first asset to withdraw -// int64 minAmountB; // minimum amount of second asset to withdraw +// int64 amount; // amount of pool shares to withdraw +// int64 minAmountA; // minimum amount of first asset to withdraw +// int64 minAmountB; // minimum amount of second asset to withdraw // }; // type LiquidityPoolWithdrawOp struct { @@ -22657,13 +22661,14 @@ var _ xdrType = (*LedgerBounds)(nil) // PreconditionsV2 is an XDR Struct defines as: // -// struct PreconditionsV2 { -// TimeBounds *timeBounds; +// struct PreconditionsV2 +// { +// TimeBounds* timeBounds; // // // Transaction only valid for ledger numbers n such that // // minLedger <= n < maxLedger (if maxLedger == 0, then // // only minLedger is checked) -// LedgerBounds *ledgerBounds; +// LedgerBounds* ledgerBounds; // // // If NULL, only valid when sourceAccount's sequence number // // is seqNum - 1. Otherwise, valid when sourceAccount's @@ -22671,7 +22676,7 @@ var _ xdrType = (*LedgerBounds)(nil) // // Note that after execution the account's sequence number // // is always raised to tx.seqNum, and a transaction is not // // valid if tx.seqNum is too high to ensure replay protection. -// SequenceNumber *minSeqNum; +// SequenceNumber* minSeqNum; // // // For the transaction to be valid, the current ledger time must // // be at least minSeqAge greater than sourceAccount's seqTime. @@ -22853,7 +22858,8 @@ var _ xdrType = (*PreconditionsV2)(nil) // PreconditionType is an XDR Enum defines as: // -// enum PreconditionType { +// enum PreconditionType +// { // PRECOND_NONE = 0, // PRECOND_TIME = 1, // PRECOND_V2 = 2 @@ -22939,13 +22945,14 @@ var _ xdrType = (*PreconditionType)(nil) // Preconditions is an XDR Union defines as: // -// union Preconditions switch (PreconditionType type) { -// case PRECOND_NONE: -// void; -// case PRECOND_TIME: -// TimeBounds timeBounds; -// case PRECOND_V2: -// PreconditionsV2 v2; +// union Preconditions switch (PreconditionType type) +// { +// case PRECOND_NONE: +// void; +// case PRECOND_TIME: +// TimeBounds timeBounds; +// case PRECOND_V2: +// PreconditionsV2 v2; // }; // type Preconditions struct { @@ -27893,10 +27900,12 @@ var _ xdrType = (*SetOptionsResult)(nil) // // cannot create with a limit of 0 // CHANGE_TRUST_LOW_RESERVE = // -4, // not enough funds to create a new trust line, -// CHANGE_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed +// CHANGE_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed // CHANGE_TRUST_TRUST_LINE_MISSING = -6, // Asset trustline is missing for pool -// CHANGE_TRUST_CANNOT_DELETE = -7, // Asset trustline is still referenced in a pool -// CHANGE_TRUST_NOT_AUTH_MAINTAIN_LIABILITIES = -8 // Asset trustline is deauthorized +// CHANGE_TRUST_CANNOT_DELETE = +// -7, // Asset trustline is still referenced in a pool +// CHANGE_TRUST_NOT_AUTH_MAINTAIN_LIABILITIES = +// -8 // Asset trustline is deauthorized // }; // type ChangeTrustResultCode int32 @@ -28107,10 +28116,10 @@ var _ xdrType = (*ChangeTrustResult)(nil) // ALLOW_TRUST_NO_TRUST_LINE = -2, // trustor does not have a trustline // // source account does not require trust // ALLOW_TRUST_TRUST_NOT_REQUIRED = -3, -// ALLOW_TRUST_CANT_REVOKE = -4, // source account can't revoke trust, +// ALLOW_TRUST_CANT_REVOKE = -4, // source account can't revoke trust, // ALLOW_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed -// ALLOW_TRUST_LOW_RESERVE = -6 // claimable balances can't be created -// // on revoke due to low reserves +// ALLOW_TRUST_LOW_RESERVE = -6 // claimable balances can't be created +// // on revoke due to low reserves // }; // type AllowTrustResultCode int32 @@ -31042,8 +31051,7 @@ var _ xdrType = (*LiquidityPoolDepositResultCode)(nil) // LiquidityPoolDepositResult is an XDR Union defines as: // -// union LiquidityPoolDepositResult switch ( -// LiquidityPoolDepositResultCode code) +// union LiquidityPoolDepositResult switch (LiquidityPoolDepositResultCode code) // { // case LIQUIDITY_POOL_DEPOSIT_SUCCESS: // void; @@ -31156,14 +31164,14 @@ var _ xdrType = (*LiquidityPoolDepositResult)(nil) // LIQUIDITY_POOL_WITHDRAW_SUCCESS = 0, // // // codes considered as "failure" for the operation -// LIQUIDITY_POOL_WITHDRAW_MALFORMED = -1, // bad input -// LIQUIDITY_POOL_WITHDRAW_NO_TRUST = -2, // no trust line for one of the -// // assets -// LIQUIDITY_POOL_WITHDRAW_UNDERFUNDED = -3, // not enough balance of the -// // pool share -// LIQUIDITY_POOL_WITHDRAW_LINE_FULL = -4, // would go above limit for one -// // of the assets -// LIQUIDITY_POOL_WITHDRAW_UNDER_MINIMUM = -5 // didn't withdraw enough +// LIQUIDITY_POOL_WITHDRAW_MALFORMED = -1, // bad input +// LIQUIDITY_POOL_WITHDRAW_NO_TRUST = -2, // no trust line for one of the +// // assets +// LIQUIDITY_POOL_WITHDRAW_UNDERFUNDED = -3, // not enough balance of the +// // pool share +// LIQUIDITY_POOL_WITHDRAW_LINE_FULL = -4, // would go above limit for one +// // of the assets +// LIQUIDITY_POOL_WITHDRAW_UNDER_MINIMUM = -5 // didn't withdraw enough // }; // type LiquidityPoolWithdrawResultCode int32 @@ -31252,8 +31260,7 @@ var _ xdrType = (*LiquidityPoolWithdrawResultCode)(nil) // LiquidityPoolWithdrawResult is an XDR Union defines as: // -// union LiquidityPoolWithdrawResult switch ( -// LiquidityPoolWithdrawResultCode code) +// union LiquidityPoolWithdrawResult switch (LiquidityPoolWithdrawResultCode code) // { // case LIQUIDITY_POOL_WITHDRAW_SUCCESS: // void; @@ -32964,7 +32971,9 @@ var _ xdrType = (*OperationResult)(nil) // txNOT_SUPPORTED = -12, // transaction type not supported // txFEE_BUMP_INNER_FAILED = -13, // fee bump inner transaction failed // txBAD_SPONSORSHIP = -14, // sponsorship not confirmed -// txBAD_MIN_SEQ_AGE_OR_GAP = -15 //minSeqAge or minSeqLedgerGap conditions not met +// txBAD_MIN_SEQ_AGE_OR_GAP = +// -15, // minSeqAge or minSeqLedgerGap conditions not met +// txMALFORMED = -16 // precondition is invalid // }; // type TransactionResultCode int32 @@ -32987,6 +32996,7 @@ const ( TransactionResultCodeTxFeeBumpInnerFailed TransactionResultCode = -13 TransactionResultCodeTxBadSponsorship TransactionResultCode = -14 TransactionResultCodeTxBadMinSeqAgeOrGap TransactionResultCode = -15 + TransactionResultCodeTxMalformed TransactionResultCode = -16 ) var transactionResultCodeMap = map[int32]string{ @@ -33007,6 +33017,7 @@ var transactionResultCodeMap = map[int32]string{ -13: "TransactionResultCodeTxFeeBumpInnerFailed", -14: "TransactionResultCodeTxBadSponsorship", -15: "TransactionResultCodeTxBadMinSeqAgeOrGap", + -16: "TransactionResultCodeTxMalformed", } // ValidEnum validates a proposed value for this enum. Implements @@ -33095,6 +33106,7 @@ var _ xdrType = (*TransactionResultCode)(nil) // // txFEE_BUMP_INNER_FAILED is not included // case txBAD_SPONSORSHIP: // case txBAD_MIN_SEQ_AGE_OR_GAP: +// case txMALFORMED: // void; // } // @@ -33143,6 +33155,8 @@ func (u InnerTransactionResultResult) ArmForSwitch(sw int32) (string, bool) { return "", true case TransactionResultCodeTxBadMinSeqAgeOrGap: return "", true + case TransactionResultCodeTxMalformed: + return "", true } return "-", false } @@ -33191,6 +33205,8 @@ func NewInnerTransactionResultResult(code TransactionResultCode, value interface // void case TransactionResultCodeTxBadMinSeqAgeOrGap: // void + case TransactionResultCodeTxMalformed: + // void } return } @@ -33286,6 +33302,9 @@ func (u InnerTransactionResultResult) EncodeTo(e *xdr.Encoder) error { case TransactionResultCodeTxBadMinSeqAgeOrGap: // Void return nil + case TransactionResultCodeTxMalformed: + // Void + return nil } return fmt.Errorf("Code (TransactionResultCode) switch value '%d' is not valid for union InnerTransactionResultResult", u.Code) } @@ -33381,6 +33400,9 @@ func (u *InnerTransactionResultResult) DecodeFrom(d *xdr.Decoder) (int, error) { case TransactionResultCodeTxBadMinSeqAgeOrGap: // Void return n, nil + case TransactionResultCodeTxMalformed: + // Void + return n, nil } return n, fmt.Errorf("union InnerTransactionResultResult has invalid Code (TransactionResultCode) switch value '%d'", u.Code) } @@ -33537,6 +33559,7 @@ var _ xdrType = (*InnerTransactionResultExt)(nil) // // txFEE_BUMP_INNER_FAILED is not included // case txBAD_SPONSORSHIP: // case txBAD_MIN_SEQ_AGE_OR_GAP: +// case txMALFORMED: // void; // } // result; @@ -34522,9 +34545,10 @@ var _ xdrType = (*Int64)(nil) // ExtensionPoint is an XDR Union defines as: // -// union ExtensionPoint switch (int v) { +// union ExtensionPoint switch (int v) +// { // case 0: -// void; +// void; // }; // type ExtensionPoint struct { @@ -35021,7 +35045,8 @@ var _ xdrType = (*PublicKey)(nil) // SignerKeyEd25519SignedPayload is an XDR NestedStruct defines as: // -// struct { +// struct +// { // /* Public key that must sign the payload. */ // uint256 ed25519; // /* Payload to be raw signed by ed25519. */ @@ -35104,7 +35129,8 @@ var _ xdrType = (*SignerKeyEd25519SignedPayload)(nil) // /* Hash of random 256 bit preimage X */ // uint256 hashX; // case SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD: -// struct { +// struct +// { // /* Public key that must sign the payload. */ // uint256 ed25519; // /* Payload to be raw signed by ed25519. */