diff --git a/services/horizon/CHANGELOG.md b/services/horizon/CHANGELOG.md index 1e761f9f4c..abf63a7c65 100644 --- a/services/horizon/CHANGELOG.md +++ b/services/horizon/CHANGELOG.md @@ -5,8 +5,7 @@ file. This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased -* Generate Http Status code of 499 for Client Disconnects, should propagate into `horizon_http_requests_duration_seconds_count` - metric key with status=499 label. ([4098](horizon_http_requests_duration_seconds_count)) +* Added `absBeforeEpoch` to ClaimableBalance API Resources. It will contain the Unix epoch representation of absolute before date. ([4148](https://github.com/stellar/go/pull/4148)) ## v2.12.1 diff --git a/services/horizon/internal/resourceadapter/claimable_balances_test.go b/services/horizon/internal/resourceadapter/claimable_balances_test.go index d83b6036c1..c7525b828b 100644 --- a/services/horizon/internal/resourceadapter/claimable_balances_test.go +++ b/services/horizon/internal/resourceadapter/claimable_balances_test.go @@ -21,6 +21,12 @@ func TestPopulateClaimableBalance(t *testing.T) { Type: xdr.ClaimableBalanceIdTypeClaimableBalanceIdTypeV0, V0: &xdr.Hash{1, 2, 3}, } + unconditional := &xdr.ClaimPredicate{ + Type: xdr.ClaimPredicateTypeClaimPredicateUnconditional, + } + relBefore := xdr.Int64(12) + absBefore := xdr.Int64(1598440539) + id, err := xdr.MarshalHex(&balanceID) tt.NoError(err) claimableBalance := history.ClaimableBalance{ @@ -32,7 +38,26 @@ func TestPopulateClaimableBalance(t *testing.T) { { Destination: "GC3C4AKRBQLHOJ45U4XG35ESVWRDECWO5XLDGYADO6DPR3L7KIDVUMML", Predicate: xdr.ClaimPredicate{ - Type: xdr.ClaimPredicateTypeClaimPredicateUnconditional, + Type: xdr.ClaimPredicateTypeClaimPredicateAnd, + AndPredicates: &[]xdr.ClaimPredicate{ + { + Type: xdr.ClaimPredicateTypeClaimPredicateOr, + OrPredicates: &[]xdr.ClaimPredicate{ + { + Type: xdr.ClaimPredicateTypeClaimPredicateBeforeRelativeTime, + RelBefore: &relBefore, + }, + { + Type: xdr.ClaimPredicateTypeClaimPredicateBeforeAbsoluteTime, + AbsBefore: &absBefore, + }, + }, + }, + { + Type: xdr.ClaimPredicateTypeClaimPredicateNot, + NotPredicate: &unconditional, + }, + }, }, }, }, @@ -74,5 +99,5 @@ func TestPopulateClaimableBalance(t *testing.T) { predicate, err := json.Marshal(resource.Claimants[0].Predicate) tt.NoError(err) - tt.JSONEq(`{"unconditional":true}`, string(predicate)) + tt.JSONEq(`{"and":[{"or":[{"rel_before":"12"},{"abs_before":"2020-08-26T11:15:39Z","abs_before_epoch":"1598440539"}]},{"not":{"unconditional":true}}]}`, string(predicate)) } diff --git a/xdr/json.go b/xdr/json.go index 78915e0afb..a22fbed0b6 100644 --- a/xdr/json.go +++ b/xdr/json.go @@ -60,13 +60,18 @@ func (t *iso8601Time) UnmarshalJSON(b []byte) error { return nil } +func newiso8601Time(epoch int64) *iso8601Time { + return &iso8601Time{time.Unix(epoch, 0).UTC()} +} + type claimPredicateJSON struct { - And *[]claimPredicateJSON `json:"and,omitempty"` - Or *[]claimPredicateJSON `json:"or,omitempty"` - Not *claimPredicateJSON `json:"not,omitempty"` - Unconditional bool `json:"unconditional,omitempty"` - AbsBefore *iso8601Time `json:"abs_before,omitempty"` - RelBefore *int64 `json:"rel_before,string,omitempty"` + And *[]claimPredicateJSON `json:"and,omitempty"` + Or *[]claimPredicateJSON `json:"or,omitempty"` + Not *claimPredicateJSON `json:"not,omitempty"` + Unconditional bool `json:"unconditional,omitempty"` + AbsBefore *iso8601Time `json:"abs_before,omitempty"` + AbsBeforeEpoch *int64 `json:"abs_before_epoch,string,omitempty"` + RelBefore *int64 `json:"rel_before,string,omitempty"` } func convertPredicatesToXDR(input []claimPredicateJSON) ([]ClaimPredicate, error) { @@ -93,7 +98,7 @@ func (c claimPredicateJSON) toXDR() (ClaimPredicate, error) { result.Type = ClaimPredicateTypeClaimPredicateBeforeRelativeTime result.RelBefore = &relBefore case c.AbsBefore != nil: - absBefore := Int64((*c.AbsBefore).UTC().Unix()) + absBefore := Int64(c.AbsBefore.UTC().Unix()) result.Type = ClaimPredicateTypeClaimPredicateBeforeAbsoluteTime result.AbsBefore = &absBefore case c.Not != nil: @@ -152,11 +157,12 @@ func (c ClaimPredicate) toJSON() (claimPredicateJSON, error) { payload.Not = new(claimPredicateJSON) *payload.Not, err = c.MustNotPredicate().toJSON() case ClaimPredicateTypeClaimPredicateBeforeAbsoluteTime: - payload.AbsBefore = new(iso8601Time) - *payload.AbsBefore = iso8601Time{time.Unix(int64(c.MustAbsBefore()), 0).UTC()} + absBeforeEpoch := int64(c.MustAbsBefore()) + payload.AbsBefore = newiso8601Time(absBeforeEpoch) + payload.AbsBeforeEpoch = &absBeforeEpoch case ClaimPredicateTypeClaimPredicateBeforeRelativeTime: - payload.RelBefore = new(int64) - *payload.RelBefore = int64(c.MustRelBefore()) + relBefore := int64(c.MustRelBefore()) + payload.RelBefore = &relBefore default: err = fmt.Errorf("invalid predicate type: " + c.Type.String()) } diff --git a/xdr/json_test.go b/xdr/json_test.go index 5576c621ad..1e72912ee7 100644 --- a/xdr/json_test.go +++ b/xdr/json_test.go @@ -46,7 +46,7 @@ func TestClaimPredicateJSON(t *testing.T) { assert.NoError(t, err) assert.JSONEq( t, - `{"and":[{"or":[{"rel_before":"12"},{"abs_before":"2020-08-26T11:15:39Z"}]},{"not":{"unconditional":true}}]}`, + `{"and":[{"or":[{"rel_before":"12"},{"abs_before":"2020-08-26T11:15:39Z","abs_before_epoch":"1598440539"}]},{"not":{"unconditional":true}}]}`, string(serialized), ) @@ -99,28 +99,28 @@ func TestAbsBeforeTimestamps(t *testing.T) { }{ { 0, - `{"abs_before":"1970-01-01T00:00:00Z"}`, + `{"abs_before":"1970-01-01T00:00:00Z","abs_before_epoch":"0"}`, }, { 900 * year, - `{"abs_before":"2869-05-27T00:00:00Z"}`, + `{"abs_before":"2869-05-27T00:00:00Z","abs_before_epoch":"28382400000"}`, }, { math.MaxInt64, - `{"abs_before":"+292277026596-12-04T15:30:07Z"}`, + `{"abs_before":"+292277026596-12-04T15:30:07Z","abs_before_epoch":"9223372036854775807"}`, }, { -10, - `{"abs_before":"1969-12-31T23:59:50Z"}`, + `{"abs_before":"1969-12-31T23:59:50Z","abs_before_epoch":"-10"}`, }, { -9000 * year, - `{"abs_before":"-7025-12-23T00:00:00Z"}`, + `{"abs_before":"-7025-12-23T00:00:00Z","abs_before_epoch":"-283824000000"}`, }, { math.MinInt64, // this serialization doesn't make sense but at least it doesn't crash the marshaller - `{"abs_before":"+292277026596-12-04T15:30:08Z"}`, + `{"abs_before":"+292277026596-12-04T15:30:08Z","abs_before_epoch":"-9223372036854775808"}`, }, } { xdrSec := Int64(testCase.unix)