diff --git a/services/horizon/CHANGELOG.md b/services/horizon/CHANGELOG.md index 8d224dbe62..a43b8ea64f 100644 --- a/services/horizon/CHANGELOG.md +++ b/services/horizon/CHANGELOG.md @@ -3,7 +3,15 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## Unreleased +## V2.17.0 + +This is the final release after the [release candidate](v2.17.0-release-candidate), including some small additional changes: + +- The transaction precondition record now excludes ([4360](https://github.com/stellar/go/pull/4360)): + * `min_account_sequence_age` when it's `"0"`, as this is the default value when the condition is not set + * `preconditions.ledgerbounds.max_ledger` when it's set to 0 (this means that there is no upper bound) + +- Timebounds within the `preconditions` object are strings containing int64 UNIX timestamps in seconds rather than formatted date-times (which was a bug) ([4361](https://github.com/stellar/go/pull/4361)). ## V2.17.0 Release Candidate @@ -40,7 +48,7 @@ file. This project adheres to [Semantic Versioning](http://semver.org/). } ``` - All of the top-level fields within this object are also optional. However, the "ledgerbounds" object will always have its inner values set. + All of the top-level fields within this object are also optional. However, the "ledgerbounds" object will always have at least its `min_ledger` field set. Note that the existing "valid_before_time" and "valid_after_time" fields on the top-level object will be identical to the "preconditions.timebounds.min_time" and "preconditions.timebounds.min_time" fields, respectively, if those exist. The "valid_before_time" and "valid_after_time" fields are now considered deprecated and will be removed in Horizon v3.0.0. diff --git a/services/horizon/internal/integration/transaction_preconditions_test.go b/services/horizon/internal/integration/transaction_preconditions_test.go index 13f29c59d6..44a6baac82 100644 --- a/services/horizon/internal/integration/transaction_preconditions_test.go +++ b/services/horizon/internal/integration/transaction_preconditions_test.go @@ -119,13 +119,23 @@ func TestTransactionPreconditionsTimeBounds(t *testing.T) { txHistory, err := itest.Client().TransactionDetail(tx.Hash) assert.NoError(t, err) - historyMaxTime, err := time.Parse(time.RFC3339, txHistory.Preconditions.TimeBounds.MaxTime) + + // Check that the deprecated string datetime fields match the new UNIX + // timestamp fields. + deprecatedHistoryMinTime, err := time.Parse(time.RFC3339, txHistory.ValidAfter) + assert.NoError(t, err) + deprecatedHistoryMaxTime, err := time.Parse(time.RFC3339, txHistory.ValidBefore) + assert.NoError(t, err) + + historyMinTime, err := strconv.ParseInt(txHistory.Preconditions.TimeBounds.MinTime, 10, 64) assert.NoError(t, err) - historyMinTime, err := time.Parse(time.RFC3339, txHistory.Preconditions.TimeBounds.MinTime) + historyMaxTime, err := strconv.ParseInt(txHistory.Preconditions.TimeBounds.MaxTime, 10, 64) assert.NoError(t, err) - assert.Equal(t, historyMaxTime.UTC().Unix(), txParams.Preconditions.TimeBounds.MaxTime) - assert.Equal(t, historyMinTime.UTC().Unix(), txParams.Preconditions.TimeBounds.MinTime) + assert.Equal(t, historyMinTime, deprecatedHistoryMinTime.UTC().Unix()) + assert.Equal(t, historyMaxTime, deprecatedHistoryMaxTime.UTC().Unix()) + assert.Equal(t, historyMinTime, txParams.Preconditions.TimeBounds.MinTime) + assert.Equal(t, historyMaxTime, txParams.Preconditions.TimeBounds.MaxTime) } func TestTransactionPreconditionsExtraSigners(t *testing.T) { diff --git a/services/horizon/internal/resourceadapter/transaction.go b/services/horizon/internal/resourceadapter/transaction.go index a72f202d36..547f8f4b40 100644 --- a/services/horizon/internal/resourceadapter/transaction.go +++ b/services/horizon/internal/resourceadapter/transaction.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "fmt" + "strconv" "time" "github.com/guregu/null" @@ -65,8 +66,8 @@ func PopulateTransaction( dest.ValidAfter = timeString(row.TimeBounds.Lower) dest.Preconditions.TimeBounds = &protocol.TransactionPreconditionsTimebounds{ - MaxTime: timeString(row.TimeBounds.Upper), - MinTime: timeString(row.TimeBounds.Lower), + MaxTime: timestampString(row.TimeBounds.Upper), + MinTime: timestampString(row.TimeBounds.Lower), } } @@ -158,3 +159,11 @@ func timeString(in null.Int) string { return time.Unix(in.Int64, 0).UTC().Format(time.RFC3339) } + +func timestampString(in null.Int) string { + if !in.Valid { + return "" + } + + return strconv.FormatInt(in.Int64, 10) +} diff --git a/services/horizon/internal/resourceadapter/transaction_test.go b/services/horizon/internal/resourceadapter/transaction_test.go index 9168f2c3e5..77246ae681 100644 --- a/services/horizon/internal/resourceadapter/transaction_test.go +++ b/services/horizon/internal/resourceadapter/transaction_test.go @@ -195,8 +195,8 @@ func TestPopulateTransaction_Preconditions(t *testing.T) { p := dest.Preconditions assert.Equal(t, validAfter.Format(time.RFC3339), dest.ValidAfter) assert.Equal(t, validBefore.Format(time.RFC3339), dest.ValidBefore) - assert.Equal(t, validAfter.Format(time.RFC3339), p.TimeBounds.MinTime) - assert.Equal(t, validBefore.Format(time.RFC3339), p.TimeBounds.MaxTime) + assert.Equal(t, fmt.Sprint(validAfter.Unix()), p.TimeBounds.MinTime) + assert.Equal(t, fmt.Sprint(validBefore.Unix()), p.TimeBounds.MaxTime) assert.Equal(t, minLedger, p.LedgerBounds.MinLedger) assert.Equal(t, maxLedger, p.LedgerBounds.MaxLedger) assert.Equal(t, fmt.Sprint(minAccountSequence), p.MinAccountSequence) @@ -289,8 +289,8 @@ func TestPopulateTransaction_PreconditionsV2(t *testing.T) { assert.NoError(t, PopulateTransaction(ctx, row.TransactionHash, &dest, row)) gotTimebounds := dest.Preconditions.TimeBounds - assert.Equal(t, "1970-01-01T00:00:05Z", gotTimebounds.MinTime) - assert.Equal(t, "1970-01-01T00:00:10Z", gotTimebounds.MaxTime) + assert.Equal(t, "5", gotTimebounds.MinTime) + assert.Equal(t, "10", gotTimebounds.MaxTime) } }