Skip to content

Connector & Engine adjustments for asset scale precision loss leftovers #199

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

Merged
merged 12 commits into from
Aug 15, 2019

Conversation

gakonst
Copy link
Collaborator

@gakonst gakonst commented Aug 8, 2019

Closes #185

@gakonst gakonst requested a review from emschwartz as a code owner August 8, 2019 10:45
@gakonst gakonst changed the base branch from master to gakonst-asset-scale August 8, 2019 10:45
@gakonst gakonst changed the title Connector & Engine adjustments for precision loss leftovers Connector & Engine adjustments for asset scale precision loss leftovers Aug 8, 2019
@gakonst gakonst force-pushed the gakonst-asset-scale branch from 4927f5d to d227963 Compare August 8, 2019 15:57
@gakonst gakonst force-pushed the gakonst-precision-loss branch from 09c89e6 to 0b8ee3f Compare August 9, 2019 09:24
@gakonst
Copy link
Collaborator Author

gakonst commented Aug 9, 2019

Adding a type_length_limit check at the main.rs file does not seem to allow tests to build:

cargo build --all-features --all-targets
   Compiling interledger-settlement-engines v0.1.0 (/Users/gakonst/projects/xpring-contract/interledger-rs/crates/interledger-settlement-engines)
error: reached the type-length limit while instantiating `<std::vec::IntoIter<ethereum_typ...]]], std::result::Result<(), !>>`
     |
     = note: consider adding a `#![type_length_limit="1689024"]` attribute to your crate

error: aborting due to previous error

error: Could not compile `interledger-settlement-engines`.
warning: build failed, waiting for other jobs to finish...
error: reached the type-length limit while instantiating `<std::vec::IntoIter<ethereum_typ...]]], std::result::Result<(), !>>`
     |
     = note: consider adding a `#![type_length_limit="1689024"]` attribute to your crate

error: aborting due to previous error

error: Could not compile `interledger-settlement-engines`.
warning: build failed, waiting for other jobs to finish...
error: reached the type-length limit while instantiating `<std::vec::IntoIter<ethereum_typ...]]], std::result::Result<(), !>>`
     |
     = note: consider adding a `#![type_length_limit="1689024"]` attribute to your crate

error: aborting due to previous error

error: Could not compile `interledger-settlement-engines`.

Error is pretty opaque, does not indicate where we need to adjust things

@gakonst gakonst force-pushed the gakonst-precision-loss branch from 05dce10 to 055d365 Compare August 9, 2019 18:01
@gakonst gakonst changed the base branch from gakonst-asset-scale to master August 9, 2019 18:01
@gakonst
Copy link
Collaborator Author

gakonst commented Aug 12, 2019

Maybe related: rust-lang/rust#54540 (comment)

Turns out boxing the futures instead of returning Either's does the trick. Not sure how I feel about it, but I cannot find another workaround.

In linkmauve/tokio-socks5@a532d63, they allude how they use Boxes to avoid long compilation times because the nested futures really make the compiler tired.

@gakonst gakonst force-pushed the gakonst-precision-loss branch from 488677e to 88dc75d Compare August 12, 2019 14:03
@gakonst gakonst requested a review from emschwartz August 12, 2019 14:04
@gakonst
Copy link
Collaborator Author

gakonst commented Aug 12, 2019

@emschwartz this should be good for review again. Curious what you think on Box'ing the futures. Seems like there's no good alternative.

Copy link
Member

@emschwartz emschwartz left a comment

Choose a reason for hiding this comment

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

I think I still prefer load_uncredited_settlement_amount and save_uncredited_settlement_amount over load/pop leftovers

) -> Box<dyn Future<Item = (), Error = ()> + Send> {
trace!("Saving leftovers {:?} {:?}", account_id, leftovers);
let mut pipe = redis::pipe();
pipe.set(format!("leftovers:{}", account_id), leftovers.to_string())
Copy link
Member

Choose a reason for hiding this comment

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

This should be adding to that amount rather than overwriting what's there

Copy link
Collaborator Author

@gakonst gakonst Aug 12, 2019

Choose a reason for hiding this comment

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

Yeah that's correct since there may be a race condition. However, the amount being written is a BigNumber, we cannot do arithmetic with these in the store, unless we store them as numbers in redis.

What should we do if the connector replies with leftovers greater than u64? Alternatively, we should explore some way to perform atomic threadsafe operations on Redis where we pull some value, operate on it and write back to it.

Copy link
Member

Choose a reason for hiding this comment

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

Kind of a janky solution but we could use a list of strings in Redis. When you want to save an amount, you would add another number to the list. When you want to get the leftovers, you would load the whole list (and empty it out -- although this creates a possibility that information would get lost if the SE crashes right then) and sum up the numbers parsed from the strings using the big integer library.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the list of strings idea. When we fetch the leftovers, I also think we can mitigate any risk of the SE crashing:

  1. Generate a new idempotency key locally
  2. Run a pipeline or Lua script that:
    a. Gets the uncredited list (and returns right away if it's empty)
    b. Sets new key(s) with the idempotency key, its expiration, and the list of amounts it corresponds to
    b. Empties the uncredited list
    d. Returns the list of amounts corresponding to the idempotency key
  3. Then, the BigNumber logic locally can sum up the list of amounts for the incoming settlement request. If it crashes and comes back online, it can safely lookup all unexpired idempotency keys, and add up their list of amounts locally to compute the total amount that should be sent in each of the incoming settlement requests.
  4. If that idempotency key expires/the request fails after a few retries, we can atomically append its list of amounts to the list of uncredited amounts and delete the idempotency key.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The list of strings logic has been added, thanks for the suggestion @emschwartz.

Ok(())
})
})
let amount = BigUint::from(100u64);
Copy link
Member

Choose a reason for hiding this comment

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

This test should use numbers that are larger than u64, just to ensure it does exactly what we expect

@gakonst gakonst requested a review from emschwartz August 13, 2019 17:13
uncredited_settlement_amount
);
let mut pipe = redis::pipe();
pipe.lpush(
Copy link
Member

Choose a reason for hiding this comment

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

Might be worth including a comment recording why these amounts are stored as a list

let mut pipe = redis::pipe();
// Loads the value and resets it to 0
pipe.lrange(
format!("uncredited_settlement_amount:{}", account_id),
Copy link
Member

Choose a reason for hiding this comment

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

Should this key be prefixed with the SE type like the other keys?

@gakonst gakonst force-pushed the gakonst-precision-loss branch from db28493 to 0d5a477 Compare August 15, 2019 16:50
@gakonst gakonst merged commit 7cfa6bf into master Aug 15, 2019
@gakonst gakonst deleted the gakonst-precision-loss branch August 15, 2019 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Settlement Engine Asset Scale
3 participants