diff --git a/services/horizon/internal/db2/history/transaction_batch_insert_builder.go b/services/horizon/internal/db2/history/transaction_batch_insert_builder.go index 77816911f1..e22fdbf096 100644 --- a/services/horizon/internal/db2/history/transaction_batch_insert_builder.go +++ b/services/horizon/internal/db2/history/transaction_batch_insert_builder.go @@ -135,7 +135,7 @@ type TransactionWithoutLedger struct { TimeBounds TimeBounds `db:"time_bounds"` LedgerBounds LedgerBounds `db:"ledger_bounds"` MinAccountSequence null.Int `db:"min_account_sequence"` - MinAccountSequenceAge null.Int `db:"min_account_sequence_age"` + MinAccountSequenceAge null.String `db:"min_account_sequence_age"` MinAccountSequenceLedgerGap null.Int `db:"min_account_sequence_ledger_gap"` ExtraSigners pq.StringArray `db:"extra_signers"` CreatedAt time.Time `db:"created_at"` @@ -234,11 +234,11 @@ func formatMinSequenceNumber(minSeqNum *int64) null.Int { return null.IntFrom(int64(*minSeqNum)) } -func formatDuration(d *xdr.Duration) null.Int { +func formatDuration(d *xdr.Duration) null.String { if d == nil { - return null.Int{} + return null.String{} } - return null.IntFrom(int64(*d)) + return null.StringFrom(fmt.Sprint(uint64(*d))) } func formatUint32(u *xdr.Uint32) null.Int { diff --git a/services/horizon/internal/db2/history/transaction_batch_insert_builder_test.go b/services/horizon/internal/db2/history/transaction_batch_insert_builder_test.go index 6cc5b78543..a41192720f 100644 --- a/services/horizon/internal/db2/history/transaction_batch_insert_builder_test.go +++ b/services/horizon/internal/db2/history/transaction_batch_insert_builder_test.go @@ -1,6 +1,8 @@ package history import ( + "fmt" + "math" "testing" "github.com/guregu/null" @@ -188,7 +190,7 @@ func TestTransactionToMap_Preconditions(t *testing.T) { Type: xdr.CryptoKeyTypeKeyTypeEd25519, Ed25519: &xdr.Uint256{3, 2, 1}, } - minSeqNum := xdr.SequenceNumber(24) + minSeqNum := xdr.SequenceNumber(math.MaxInt64) signerKey := xdr.SignerKey{ Type: xdr.SignerKeyTypeSignerKeyTypeEd25519, Ed25519: source.Ed25519, @@ -226,7 +228,7 @@ func TestTransactionToMap_Preconditions(t *testing.T) { MaxLedger: 10, }, MinSeqNum: &minSeqNum, - MinSeqAge: xdr.Duration(1024), + MinSeqAge: xdr.Duration(math.MaxUint64), MinSeqLedgerGap: xdr.Uint32(3), ExtraSigners: []xdr.SignerKey{signerKey}, }, @@ -272,8 +274,8 @@ func TestTransactionToMap_Preconditions(t *testing.T) { assert.Equal(t, null.IntFrom(5), row.LedgerBounds.MinLedger) assert.Equal(t, null.IntFrom(10), row.LedgerBounds.MaxLedger) - assert.Equal(t, null.IntFrom(24), row.MinAccountSequence) - assert.Equal(t, null.IntFrom(1024), row.MinAccountSequenceAge) + assert.Equal(t, null.IntFrom(int64(minSeqNum)), row.MinAccountSequence) + assert.Equal(t, null.StringFrom(fmt.Sprint(uint64(math.MaxUint64))), row.MinAccountSequenceAge) assert.Equal(t, null.IntFrom(3), row.MinAccountSequenceLedgerGap) assert.Equal(t, pq.StringArray{signerKey.Address()}, row.ExtraSigners) } diff --git a/services/horizon/internal/db2/history/transaction_test.go b/services/horizon/internal/db2/history/transaction_test.go index f022ef5c44..7c491fe54d 100644 --- a/services/horizon/internal/db2/history/transaction_test.go +++ b/services/horizon/internal/db2/history/transaction_test.go @@ -776,7 +776,7 @@ func TestInsertTransaction(t *testing.T) { TimeBounds: v2TimeboundsWithMinAndMax, LedgerBounds: v2LedgerboundsWithMinAndMax, MinAccountSequence: null.Int{}, - MinAccountSequenceAge: null.IntFrom(10), + MinAccountSequenceAge: null.StringFrom("10"), MinAccountSequenceLedgerGap: null.IntFrom(2), ExtraSigners: pq.StringArray{}, Successful: success, diff --git a/services/horizon/internal/db2/schema/bindata.go b/services/horizon/internal/db2/schema/bindata.go index f18c2a8686..6e3e6bbd20 100644 --- a/services/horizon/internal/db2/schema/bindata.go +++ b/services/horizon/internal/db2/schema/bindata.go @@ -49,7 +49,7 @@ // migrations/51_remove_ht_unused_indexes.sql (321B) // migrations/52_add_trade_type_index.sql (424B) // migrations/53_add_trades_rounding_slippage.sql (274B) -// migrations/54_tx_preconditions_and_account_fields.sql (1.219kB) +// migrations/54_tx_preconditions_and_account_fields.sql (1.355kB) // migrations/5_create_trades_table.sql (1.1kB) // migrations/6_create_assets_table.sql (366B) // migrations/7_modify_trades_table.sql (2.303kB) @@ -1104,7 +1104,7 @@ func migrations53_add_trades_rounding_slippageSql() (*asset, error) { return a, nil } -var _migrations54_tx_preconditions_and_account_fieldsSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x92\xc1\x6e\xd3\x40\x10\x86\xef\x7e\x8a\xff\x56\x28\x75\x00\xa9\x54\x88\x9c\xd2\x26\xb7\x40\xa3\x92\x1e\x10\x42\xd6\xc4\x3b\xda\x2c\xd8\xb3\x61\x77\xdc\x24\x3c\x3d\xb2\x5d\x02\x0e\x89\x30\x4a\x7d\xf5\xce\x37\xf3\xcf\x7c\x69\x8a\x17\xa5\xb3\x81\x94\x71\xbf\x4a\x46\xd3\xf9\xe4\x0e\xf3\xd1\xf5\x74\x82\xa5\x8b\xea\xc3\x36\xd3\x40\x12\x29\x57\xe7\x25\x62\x34\x1e\xa3\x60\x63\x39\x64\x0b\x5f\x89\x89\xf8\xfb\x73\xa2\x6f\x03\x89\xe5\x61\x3f\x5e\xe9\x24\xa3\x3c\xf7\x95\x68\x16\xf9\x7b\xc5\x92\xf3\x9f\xbc\x85\xb3\x4e\xf4\x04\x58\x46\x96\x9f\x0e\xf6\x18\xdf\xd2\xea\xff\x60\xbc\xd1\x40\x59\x74\x56\x38\x1c\x5a\x9b\xf2\x46\x3f\x7f\x19\x26\x1d\xda\x63\xf7\x96\xb0\x37\x42\xbd\x68\xb6\x1c\x86\x3d\x2a\xd4\x95\xbc\x1b\x37\x49\x53\xdc\x8c\x66\xe9\xe5\x2b\x34\xe3\x18\xac\x68\x5b\x78\x32\x88\x1a\xbe\xf1\x36\x22\x27\xc1\x82\xf1\xfa\xea\x0d\xf2\x25\x05\xca\xb5\x9e\xb9\xf0\x62\x2f\x10\x99\x6b\x40\xfb\xf4\x65\x49\x4e\x06\xd6\xbf\x2b\x69\x33\x91\xdc\x1b\x36\x1f\xdd\x0f\x1e\xe0\xba\x52\xac\xf9\xac\x28\x50\x45\x6e\xb2\x61\xc9\x81\x2f\x10\x3d\xd6\x0c\xe3\xe5\x4c\x21\xcc\x06\xea\x6b\x1c\x99\xaf\x55\x54\x38\xc5\x39\x3f\x70\x00\x59\x72\x72\x3e\x38\x18\xed\xd7\x12\x13\xa0\xfd\x7d\x73\x3b\xbd\x7f\xff\xa1\x0d\x13\x30\xff\x34\x9b\x34\x1d\xdb\xa4\x3b\xbf\xc7\x7e\x2d\xff\x3e\xd5\xf8\xee\x76\xd6\x55\xbc\xc7\x7d\x9b\xa2\x43\xb6\x9c\x52\x5b\x6b\x7b\x52\xfd\x6f\x53\xfb\x62\x3a\x8e\x1e\x53\xb1\x79\xb9\xd7\xe4\x88\x83\xdd\xa7\xb5\x84\x47\xa0\x7d\x4e\xba\x33\x11\x0f\x14\xb6\x4e\xec\xb3\xab\xcb\xe7\xc3\xe4\x67\x00\x00\x00\xff\xff\x47\xa1\x27\x97\xc3\x04\x00\x00") +var _migrations54_tx_preconditions_and_account_fieldsSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x54\xcd\x6e\xda\x40\x10\xbe\xfb\x29\xe6\x96\x9f\xc6\x34\x4d\x29\xaa\x6a\xa9\x12\x09\x1c\x2a\xd1\x04\x25\x70\xa8\xaa\xca\x1a\xbc\xa3\x65\x5b\x7b\x96\xee\x8e\x03\xf4\xe9\xab\xb5\x81\x14\x8a\x55\xab\x70\x62\xed\x99\xf9\x7e\xf6\x1b\xc7\x31\xbc\x2a\x8c\x76\x28\x04\xd3\x45\xd4\x1f\x4d\x86\x8f\x30\xe9\xdf\x8e\x86\x30\x37\x5e\xac\x5b\xa7\xe2\x90\x3d\x66\x62\x2c\x7b\xe8\x0f\x06\x90\x93\xd2\xe4\xd2\x99\x2d\x59\x79\xf8\xfb\x67\x58\xde\x3b\x64\x4d\x49\x75\x8c\x63\x58\x29\xd7\x99\x1a\x96\xb7\x37\xbe\x1d\x44\x61\x38\xc5\x2c\xb3\x25\x4b\xea\xe9\x67\x49\x9c\xd1\x9f\x10\x33\xa3\x0d\x4b\xb2\x3d\x6e\x20\x9e\x36\x95\xf7\x65\x31\x23\x07\xf1\xc7\x40\xa5\xd7\xfd\x7f\xc8\x14\xf5\x0e\xf6\x19\x5d\x36\x47\x77\x7e\x73\x7d\x91\xbc\x40\x4e\x4c\x41\x63\x6b\x58\x02\x5a\x59\xc1\x85\x7f\xb9\x65\x4d\x5e\xb6\x4f\xb8\x22\x74\x02\x8f\x8d\xe5\x1a\x17\x0d\xd2\x3f\x05\x73\xdb\x01\xd0\x4a\x1c\xa6\xde\x68\x26\x77\xec\xfa\x84\x56\xf2\xf5\x5b\x12\xed\x4d\xdb\x30\xaa\x27\x1c\xd0\x0a\x2e\x93\x26\x97\xb4\xe8\x10\x53\xd0\x56\x42\x14\xc5\x31\xdc\xf5\xc7\x71\xf7\x1a\x2a\x3a\x0a\x16\xb8\xce\x2d\x2a\xf0\xe2\x7e\xd0\xda\x43\x86\x0c\x33\x82\x37\xbd\x77\x10\xcc\xc7\x4c\x02\xe7\xe0\xee\x15\x78\xa2\x30\xa0\x2e\x7d\x5d\xa0\xe1\x8e\xb6\x1f\x0a\x5c\x0d\x39\xb3\x8a\xd4\x93\xf9\x45\x1d\xb8\x2d\x05\x96\x74\x96\xe7\x50\x7a\xaa\xb4\xc1\x9c\x1c\x5d\x81\xb7\xb0\x24\x50\x96\xcf\x04\x98\x48\x81\xd8\x30\x0e\xd5\xf7\xd2\x0b\x18\x81\x4b\x7a\x26\x07\xa8\xd1\xf0\x65\xe7\xa8\xb4\xad\x89\x11\x40\xfd\xfa\xee\x61\x34\xfd\x7c\x5f\x8b\x71\x30\xf9\x32\x1e\x56\x88\xb5\xd2\xdd\x9e\x0d\xec\x92\xff\x7d\x55\x83\xc7\x87\xf1\xfe\xaa\x25\x2d\x9b\x8e\x25\xe8\x94\xde\xb0\x05\x27\xf5\xbf\xa4\xb7\xed\x98\xbd\x8c\x36\x45\xb1\xaa\x3c\x00\x69\xc8\xe0\x7e\x69\x08\x61\xc3\xd0\x36\x57\xba\x4b\x62\xf8\x26\xac\x0d\xeb\xf3\x5e\xf7\x22\x89\x7e\x07\x00\x00\xff\xff\x09\xc0\xc0\xa1\x4b\x05\x00\x00") func migrations54_tx_preconditions_and_account_fieldsSqlBytes() ([]byte, error) { return bindataRead( @@ -1120,7 +1120,7 @@ func migrations54_tx_preconditions_and_account_fieldsSql() (*asset, error) { } info := bindataFileInfo{name: "migrations/54_tx_preconditions_and_account_fields.sql", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0xbd, 0x7f, 0x4d, 0x6a, 0x95, 0x2c, 0xa, 0x84, 0xd9, 0x2, 0x5d, 0xee, 0x66, 0xef, 0x89, 0x92, 0x97, 0xa0, 0x6f, 0x1c, 0xeb, 0x2a, 0x62, 0xc7, 0x56, 0x57, 0xe5, 0xeb, 0x2c, 0x57, 0x8f}} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa2, 0x72, 0xbe, 0x5c, 0xbd, 0xfb, 0xfd, 0x70, 0xf0, 0x2f, 0x4e, 0x76, 0x36, 0x7b, 0xb9, 0xd5, 0xfb, 0x25, 0xe8, 0x13, 0xb1, 0xf6, 0x59, 0x9d, 0xac, 0xec, 0xc3, 0x6b, 0xbe, 0x8f, 0xae, 0xb3}} return a, nil } diff --git a/services/horizon/internal/db2/schema/migrations/54_tx_preconditions_and_account_fields.sql b/services/horizon/internal/db2/schema/migrations/54_tx_preconditions_and_account_fields.sql index 87e2ab73b2..5c2a3da6ea 100644 --- a/services/horizon/internal/db2/schema/migrations/54_tx_preconditions_and_account_fields.sql +++ b/services/horizon/internal/db2/schema/migrations/54_tx_preconditions_and_account_fields.sql @@ -1,8 +1,8 @@ -- +migrate Up -ALTER TABLE history_transactions ADD ledger_bounds int8range; -ALTER TABLE history_transactions ADD min_account_sequence bigint; -ALTER TABLE history_transactions ADD min_account_sequence_age bigint; -ALTER TABLE history_transactions ADD min_account_sequence_ledger_gap bigint; +ALTER TABLE history_transactions ADD ledger_bounds int8range; -- xdr.Uint32s +ALTER TABLE history_transactions ADD min_account_sequence bigint; -- xdr.SequenceNumber -> int64 +ALTER TABLE history_transactions ADD min_account_sequence_age varchar(20); -- xdr.TimePoint -> uint64 -> longest uint64 number +ALTER TABLE history_transactions ADD min_account_sequence_ledger_gap bigint; -- xdr.Int32 ALTER TABLE history_transactions ADD extra_signers text[]; ALTER TABLE accounts ADD sequence_ledger integer; diff --git a/services/horizon/internal/integration/transaction_preconditions_test.go b/services/horizon/internal/integration/transaction_preconditions_test.go index 9ef6ce971d..f66e97d295 100644 --- a/services/horizon/internal/integration/transaction_preconditions_test.go +++ b/services/horizon/internal/integration/transaction_preconditions_test.go @@ -1,6 +1,7 @@ package integration import ( + "fmt" "strconv" "sync" "testing" @@ -218,9 +219,11 @@ func TestTransactionPreconditionsMinSequenceNumberAge(t *testing.T) { tt.Len(ledgers.Embedded.Records, 1) // gather up the current sequence times - acctSeqTime, err := strconv.ParseInt(latestMasterAccount.SequenceTime, 10, 64) + signedAcctSeqTime, err := strconv.ParseInt(latestMasterAccount.SequenceTime, 10, 64) tt.NoError(err) - networkSeqTime := ledgers.Embedded.Records[0].ClosedAt.UTC().Unix() + tt.GreaterOrEqual(signedAcctSeqTime, int64(0)) + acctSeqTime := uint64(signedAcctSeqTime) + networkSeqTime := uint64(ledgers.Embedded.Records[0].ClosedAt.UTC().Unix()) // build a tx with seqnum based on master.seqNum+1 as source account txParams := buildTXParams(master, masterAccount, currentAccountSeq+1) @@ -241,7 +244,8 @@ func TestTransactionPreconditionsMinSequenceNumberAge(t *testing.T) { //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.Equal(t, txHistory.Preconditions.MinAccountSequenceAge, strconv.FormatInt(txParams.Preconditions.MinSequenceNumberAge, 10)) + assert.EqualValues(t, txHistory.Preconditions.MinAccountSequenceAge, + fmt.Sprint(uint64(txParams.Preconditions.MinSequenceNumberAge))) } func TestTransactionPreconditionsMinSequenceNumberLedgerGap(t *testing.T) { diff --git a/services/horizon/internal/resourceadapter/transaction.go b/services/horizon/internal/resourceadapter/transaction.go index 19d4a371ca..5b785a864e 100644 --- a/services/horizon/internal/resourceadapter/transaction.go +++ b/services/horizon/internal/resourceadapter/transaction.go @@ -88,7 +88,7 @@ func PopulateTransaction( } if row.MinAccountSequenceAge.Valid { - dest.Preconditions.MinAccountSequenceAge = fmt.Sprint(row.MinAccountSequenceAge.Int64) + dest.Preconditions.MinAccountSequenceAge = row.MinAccountSequenceAge.String } if row.MinAccountSequenceLedgerGap.Valid { diff --git a/services/horizon/internal/resourceadapter/transaction_test.go b/services/horizon/internal/resourceadapter/transaction_test.go index ef77e5fdfb..6bad754ef8 100644 --- a/services/horizon/internal/resourceadapter/transaction_test.go +++ b/services/horizon/internal/resourceadapter/transaction_test.go @@ -164,12 +164,12 @@ func TestPopulateTransaction_Preconditions(t *testing.T) { row history.Transaction ) - validAfter := time.Now().Add(-1 * time.Hour) - validBefore := time.Now().Add(1 * time.Hour) + validAfter := time.Now().UTC().Add(-1 * time.Hour) + validBefore := time.Now().UTC().Add(1 * time.Hour) minLedger := uint32(40071006 - 1024) maxLedger := uint32(40071006 + 1024) minAccountSequence := int64(10) - minSequenceAge := 30 * time.Second * 1000 + minSequenceAge := uint64(30 * 1000) minSequenceLedgerGap := uint32(5) dest = Transaction{} @@ -184,7 +184,7 @@ func TestPopulateTransaction_Preconditions(t *testing.T) { MaxLedger: null.IntFrom(int64(maxLedger)), }, MinAccountSequence: null.IntFrom(minAccountSequence), - MinAccountSequenceAge: null.IntFrom(int64(minSequenceAge)), + MinAccountSequenceAge: null.StringFrom(fmt.Sprint(minSequenceAge)), MinAccountSequenceLedgerGap: null.IntFrom(int64(minSequenceLedgerGap)), ExtraSigners: pq.StringArray{"D34DB33F", "8BADF00D"}, }, @@ -199,7 +199,7 @@ func TestPopulateTransaction_Preconditions(t *testing.T) { assert.Equal(t, minLedger, p.Ledgerbounds.MinLedger) assert.Equal(t, maxLedger, p.Ledgerbounds.MaxLedger) assert.Equal(t, fmt.Sprint(minAccountSequence), p.MinAccountSequence) - assert.Equal(t, fmt.Sprint(int64(minSequenceAge)), p.MinAccountSequenceAge) + assert.Equal(t, fmt.Sprint(uint64(minSequenceAge)), p.MinAccountSequenceAge) assert.Equal(t, minSequenceLedgerGap, p.MinAccountSequenceLedgerGap) assert.Equal(t, []string{"D34DB33F", "8BADF00D"}, p.ExtraSigners) } diff --git a/txnbuild/preconditions.go b/txnbuild/preconditions.go index 76015c9335..47ff895f6c 100644 --- a/txnbuild/preconditions.go +++ b/txnbuild/preconditions.go @@ -19,7 +19,7 @@ type Preconditions struct { // Transaction is valid if the current ledger time is at least // minSequenceNumberAge greater than the source account's seqTime (units are // seconds). - MinSequenceNumberAge int64 + MinSequenceNumberAge uint64 // Transaction is valid if the current ledger number is at least // minSequenceNumberLedgerGap greater than the source account's seqLedger. MinSequenceNumberLedgerGap uint32 @@ -135,7 +135,7 @@ func (cond *Preconditions) FromXDR(precondXdr xdr.Preconditions) error { cond.MinSequenceNumber = &minSeqNum } - cond.MinSequenceNumberAge = int64(inner.MinSeqAge) + cond.MinSequenceNumberAge = uint64(inner.MinSeqAge) cond.MinSequenceNumberLedgerGap = uint32(inner.MinSeqLedgerGap) if len(inner.ExtraSigners) > 0 { cond.ExtraSigners = make([]string, len(inner.ExtraSigners))