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

Fix sum of asset in circulation in all assets endpoint #436

Merged
merged 3 commits into from
May 9, 2018

Conversation

bartekn
Copy link
Contributor

@bartekn bartekn commented May 7, 2018

Currently we hold sum of asset in circulation in int64 variable. Given
that issuer can send MAX_INT64 of an asset to each of it's trustors
it's very easy to overflow the type.

This commit changes the type a variable that holds DB result for a query
to string and adds a new function in amount package to convert
string integer to Stellar amount.

Currently we hold sum of asset in circulation in `int64` variable. Given
that issuer can send `MAX_INT64` of an asset to each of it's trustees
it's very easy to overflow the type.

This commit changes the type a variable that holds DB result for a query
to `string` and adds a new function in `amount` package to convert
string integer to Stellar amount.
@bartekn bartekn force-pushed the fix-sum-asset-aggregations branch from 11692c4 to 4cbce8a Compare May 7, 2018 18:01
@nikhilsaraf
Copy link
Contributor

@bartekn how does this affect data that is already in the table --do we need an upgrade script or an compatibility code?

@bartekn
Copy link
Contributor Author

bartekn commented May 8, 2018

We probably need to reingest the history.
EDIT Thanks for explaining this during a call @nikhilsaraf, you're right, we don't need to reingest history, a simple script that updates the data should be enough.

@@ -15,7 +15,7 @@ func TestAssetsStatsQExec(t *testing.T) {
Type: "credit_alphanum4",
Code: "BTC",
Issuer: "GC23QF2HUE52AMXUFUH3AYJAXXGXXV2VHXYYR6EYXETPKDXZSAW67XO4",
Amount: 1009876000,
Amount: "1009876000",
Copy link
Contributor

Choose a reason for hiding this comment

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

@bartekn should this be 1009876000 * 10^7 = "10098760000000000"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's converted in resources.AssetStat.Populate.

Count int32 `db:"count"`
Sum int64 `db:"sum"`
Count int32 `db:"count"`
Sum string `db:"sum"`
Copy link
Contributor

Choose a reason for hiding this comment

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

the query below var selectBalances = sq.Select("COUNT(*)", "COALESCE(SUM(balance), 0) as sum").From("trustlines") will also need to change since balance is an int so will the DB's SUM operation overflow and wil lthat return an int64 or a string? fyi @bartekn

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point which also shows we need a test for this SUM(balance) larger than bigint.

Copy link
Contributor

Choose a reason for hiding this comment

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

yup

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, it seems we're good here because postgres returns numeric type for sum of bigints and balance field in core is bigint. But I will add the test anyway tomorrow.

@@ -128,7 +128,7 @@ type Asset struct {
// AssetStat is a row in the asset_stats table representing the stats per Asset
type AssetStat struct {
ID int64 `db:"id"`
Amount int64 `db:"amount"`
Amount string `db:"amount"`
Copy link
Contributor

Choose a reason for hiding this comment

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

this will need the db upgrade script like we discussed on slack -- change the row in the assetStats table to be a character varying instead of a bigint

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added.

@nikhilsaraf
Copy link
Contributor

Added some inline comments.

Summarizing our discussion on slack, @bartekn:
General approach we discussed on slack at least for immediate fix was to convert the amount field in the db to a varchar as a db upgrade script, this will fix the value in the db so the stats table can hold the value correctly, and the code changes in the PR here will ensure that the runtime logic can support calculations that exceed the capacity of int64.

Copy link
Contributor

@nikhilsaraf nikhilsaraf left a comment

Choose a reason for hiding this comment

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

commented on migrations

@@ -102,7 +102,7 @@ SET default_with_oids = false;

CREATE TABLE asset_stats (
id bigint NOT NULL,
amount bigint NOT NULL,
amount character varying NOT NULL,
Copy link
Contributor

Choose a reason for hiding this comment

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

isn't this supposed to be left as-is?? @bartekn
anyone who starts a fresh install will go through both scripts so they will end up with the correct version.

Copy link
Contributor Author

@bartekn bartekn May 8, 2018

Choose a reason for hiding this comment

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

AFAIK, latest.sql should contain the schema dump after applying all migrations. From @nullstyle:

The latest schema allows a new database to go from empty to the correct schema without all of the intermediary steps. This becomes important when you hit 50+ migrations.

#86 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

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

ok good to know. so I guess there's some logic which knows when to apply latest vs migrations

Copy link
Contributor

@nullstyle nullstyle May 9, 2018

Choose a reason for hiding this comment

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

@nikhilsaraf latest.sql isused when you invoke horizon db init

Copy link
Contributor

Choose a reason for hiding this comment

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

ok, just for my curiosity.. do we also then run migrations after that and how would it interact in a case where the latest.sql already has the correct data-type for the column and we try and update it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, just for my curiosity.. do we also then run migrations after that and how would it interact in a case where the latest.sql already has the correct data-type for the column and we try and update it?

latest.sql also adds rows to gorp_migrations table which is later used by migrations code. Thanks for reminding me that I should add a new row there, fixed in fe74c26.

@@ -0,0 +1,7 @@
-- +migrate Up
ALTER TABLE asset_stats
ALTER COLUMN amount SET DATA TYPE character varying;
Copy link
Contributor

Choose a reason for hiding this comment

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

does this need a "using" like below?
-- also we need this to be multiplied by 10^7?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

does this need a "using" like below?

I tested it, it was only required for down migration.

also we need this to be multiplied by 10^7?

No, amount in asset_stats table is in stroops. We convert it to lumens in resources.AssetStat.Populate.

@nikhilsaraf
Copy link
Contributor

@bartekn ok sounds good. this just leaves one issue to be resolved: about the selectBalances query

nullstyle
nullstyle previously approved these changes May 9, 2018
Copy link
Contributor

@nullstyle nullstyle left a comment

Choose a reason for hiding this comment

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

LGTM!

@bartekn
Copy link
Contributor Author

bartekn commented May 9, 2018

OK, on the test front I think I need to create a new DB test scenario with a few accounts with MAX_INT64 balances. To do this I need to use scc which I have no experience with. Given we want to push this update asap, I checked if everything works on my local testnet node (created issuing account and 3 holders), result:

      {
        "_links": {
          "toml": {
            "href": ""
          }
        },
        "asset_type": "credit_alphanum4",
        "asset_code": "ABC",
        "asset_issuer": "GCXECIYXCLVDSGQJJEGCPR6FJVK4DR3GF655KT7LVRPXNRSMY5YILZVO",
        "paging_token": "ABC_GCXECIYXCLVDSGQJJEGCPR6FJVK4DR3GF655KT7LVRPXNRSMY5YILZVO_credit_alphanum4",
        "amount": "2767011611055.4327421",
        "num_accounts": 3,
        "flags": {
          "auth_required": false,
          "auth_revocable": false
        }
      },

I'll add a test later.

Copy link
Contributor

@nikhilsaraf nikhilsaraf left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@bartekn bartekn merged commit 8760b02 into master May 9, 2018
@bartekn bartekn deleted the fix-sum-asset-aggregations branch May 9, 2018 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants