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

vat-bank.js Exo nonce guards cause failures #10928

Open
michaelfig opened this issue Feb 2, 2025 · 5 comments · May be fixed by #10929
Open

vat-bank.js Exo nonce guards cause failures #10928

michaelfig opened this issue Feb 2, 2025 · 5 comments · May be fixed by #10929
Assignees
Labels
bug Something isn't working

Comments

@michaelfig
Copy link
Member

michaelfig commented Feb 2, 2025

Describe the bug

When a VBANK_BALANCE_UPDATE is sent from agd to cause a vpurse balance update, it fails instead with a logged error.

To Reproduce

Steps to reproduce the behavior:

  1. Start an Agoric chain with at least SwingSet debug logs DEBUG=SwingSet:vat
  2. Monitor log output
  3. See error (I've attached details which are visible if you expand the triangle below)
v14: Error updating balance ...
2025-01-27T17:00:32.948Z SwingSet: vat: v14: Error updating balance { address: 'agoric13fymc0q63lwkpe3wjd4tmjm5vrp9zhvt8gkhly', amount: '1000500', denom: 'ibc/65D0BEC6DAD96C7F5043D1E54E54B6BB5D5B3AEC3FF6CEBB75B9E059F3580EA3' } (Error#58)
2025-01-27T17:00:32.948Z SwingSet: vat: v14: Error#58: In "update" method of (BalanceUpdater): arg 1?: number (a number) - Must be a string
2025-01-27T17:00:32.949Z SwingSet: vat: v14: Error: In "update" method of (BalanceUpdater): arg 1?: number (a number) - Must be a string
 at apply ()
 at Error (/bundled-source/.../node_modules/ses/src/error/tame-error-constructor.js:60)
 at makeError (/bundled-source/.../node_modules/ses/src/error/assert.js:352)
 at throwLabeled (/bundled-source/.../node_modules/@endo/common/throw-labeled.js:26)
 at applyLabelingError (/bundled-source/.../node_modules/@endo/common/apply-labeling-error.js:43)
 at mustMatch (/bundled-source/.../node_modules/@endo/patterns/src/patterns/patternMatchers.js:591)
 at defendSyncArgs (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:82)
 at In "update" method of (BalanceUpdater) (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:170)
 at fromBridge (.../vats/src/vat-bank.js:208)
 at fromBridge (.../vats/src/vat-bank.js:190)
 at apply ()
 at In "fromBridge" method of (BankChannelHandler) (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:171)
 at apply ()
 at localApplyMethod (/bundled-source/.../node_modules/@endo/eventual-send/src/local.js:126)
 at apply ()
 at dispatchToHandler (/bundled-source/.../node_modules/@endo/eventual-send/src/handled-promise.js:159)
 at win (/bundled-source/.../node_modules/@endo/eventual-send/src/handled-promise.js:511)
 at ()

2025-01-27T17:00:32.949Z SwingSet: vat: v14: Error#58 ERROR_NOTE: Caused by (Error#59)
2025-01-27T17:00:32.949Z SwingSet: vat: v14: Error#59: arg 1?: number (a number) - Must be a string
2025-01-27T17:00:32.949Z SwingSet: vat: v14: Error: arg 1?: number (a number) - Must be a string
 at apply ()
 at Error (/bundled-source/.../node_modules/ses/src/error/tame-error-constructor.js:60)
 at makeError (/bundled-source/.../node_modules/ses/src/error/assert.js:352)
 at throwLabeled (/bundled-source/.../node_modules/@endo/common/throw-labeled.js:26)
 at applyLabelingError (/bundled-source/.../node_modules/@endo/common/apply-labeling-error.js:43)
 at every ()
 at checkMatches (/bundled-source/.../node_modules/@endo/patterns/src/patterns/patternMatchers.js:1367)
 at applyLabelingError (/bundled-source/.../node_modules/@endo/common/apply-labeling-error.js:41)
 at mustMatch (/bundled-source/.../node_modules/@endo/patterns/src/patterns/patternMatchers.js:591)
 at defendSyncArgs (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:82)
 at In "update" method of (BalanceUpdater) (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:170)
 at fromBridge (.../vats/src/vat-bank.js:208)
 at fromBridge (.../vats/src/vat-bank.js:190)
 at apply ()
 at In "fromBridge" method of (BankChannelHandler) (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:171)
 at apply ()
 at localApplyMethod (/bundled-source/.../node_modules/@endo/eventual-send/src/local.js:126)
 at apply ()
 at dispatchToHandler (/bundled-source/.../node_modules/@endo/eventual-send/src/handled-promise.js:159)
 at win (/bundled-source/.../node_modules/@endo/eventual-send/src/handled-promise.js:511)
 at ()

2025-01-27T17:00:32.950Z SwingSet: vat: v14: Error#59 ERROR_NOTE: Caused by (Error#60)
2025-01-27T17:00:32.950Z SwingSet: vat: v14: Error#60: number 20 - Must be a string
2025-01-27T17:00:32.950Z SwingSet: vat: v14: Error: number (a number) - Must be a string
 at apply ()
 at Error (/bundled-source/.../node_modules/ses/src/error/tame-error-constructor.js:60)
 at makeError (/bundled-source/.../node_modules/ses/src/error/assert.js:352)
 at fail (/bundled-source/.../node_modules/ses/src/error/assert.js:482)
 at baseAssert (/bundled-source/.../node_modules/ses/src/error/assert.js:504)
 at assertChecker (/bundled-source/.../node_modules/@endo/pass-style/src/passStyle-helpers.js:77)
 at checkKind (/bundled-source/.../node_modules/@endo/patterns/src/patterns/patternMatchers.js:287)
 at checkMatches (/bundled-source/.../node_modules/@endo/patterns/src/patterns/patternMatchers.js:959)
 at applyLabelingError (/bundled-source/.../node_modules/@endo/common/apply-labeling-error.js:41)
 at every ()
 at checkMatches (/bundled-source/.../node_modules/@endo/patterns/src/patterns/patternMatchers.js:1367)
 at applyLabelingError (/bundled-source/.../node_modules/@endo/common/apply-labeling-error.js:41)
 at mustMatch (/bundled-source/.../node_modules/@endo/patterns/src/patterns/patternMatchers.js:591)
 at defendSyncArgs (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:82)
 at In "update" method of (BalanceUpdater) (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:170)
 at fromBridge (.../vats/src/vat-bank.js:208)
 at fromBridge (.../vats/src/vat-bank.js:190)
 at apply ()
 at In "fromBridge" method of (BankChannelHandler) (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:171)
 at apply ()
 at localApplyMethod (/bundled-source/.../node_modules/@endo/eventual-send/src/local.js:126)
 at apply ()
 at dispatchToHandler (/bundled-source/.../node_modules/@endo/eventual-send/src/handled-promise.js:159)
 at win (/bundled-source/.../node_modules/@endo/eventual-send/src/handled-promise.js:511)
 at ()

Expected behavior

No error.

Platform Environment

  • what OS are you using? GitHub CI (ubuntu-latest CI worker)
  • what version of Node.js? v18 / CI version
  • is there anything special/unusual about your platform? CI
  • what version of the Agoric-SDK are you using? (run git describe --tags --always) agoric-upgrade-16av-1785-g3d64bee5b5

Additional context

I traced the error to the BalanceUpdaterI interface guard in vat-bank. The change in #8544 made the former undefined nonce (which had successfully passed the guard in the past) become a Golang int64 encoded as a JS number (which the guard was unprepared to accept). Both values were correctly handled by the updater.update method, but the guard failed to accommodate nonce: number values.

@michaelfig michaelfig added the bug Something isn't working label Feb 2, 2025
@michaelfig michaelfig self-assigned this Feb 2, 2025
@michaelfig michaelfig linked a pull request Feb 2, 2025 that will close this issue
@michaelfig
Copy link
Member Author

@turadg, your #10929 (comment) made me realise that I was wrong. Digging further into this, I found that int64 and uint64 fields are json.Marshalled by default into JSON-represented numbers, with no regard for Javascript's 53-bit safe integers. It is proto3 JSON that marshals int64 and uint64 types to and from JSON strings containing the digits to ensure they don't lose precision in Javascript's JSON.parse or JSON.stringify.

Thus, I gave bad advice in #8544; I know now that nearly all bridge actions are json.Marshalled, so they end up with JSON numbers instead of strings. I'd like to propose to use #10929 to revert my bad typing advice given in #8544, instead using number for int64 and uint64, and use the more tolerant guarding of nonce that I added to that PR, with more thorough commentary.

It's unfortunate that we may encounter loss of precision in the bridge messages. If we instead decide on
incompatibly changing certain bridge messages' int64, uint64 JSON marshalling to send and receive strings, we can do so with the string directive in the json: field annotation, like:

diff --git a/golang/cosmos/x/vbank/vbank.go b/golang/cosmos/x/vbank/vbank.go
index 1a0ad037cd..90ee6e7b7d 100644
--- a/golang/cosmos/x/vbank/vbank.go
+++ b/golang/cosmos/x/vbank/vbank.go
@@ -69,7 +69,7 @@ func (vbu vbankManyBalanceUpdates) Swap(i int, j int) {
 
 type VbankBalanceUpdate struct {
        *vm.ActionHeader `actionType:"VBANK_BALANCE_UPDATE"`
-       Nonce            uint64                  `json:"nonce"`
+       Nonce            uint64                  `json:"nonce,string"`
        Updated          vbankManyBalanceUpdates `json:"updated"`
 }
 

Thoughts?

@turadg
Copy link
Member

turadg commented Feb 3, 2025

I see. I think it comes down to whether we can change the serialization. If it's number, then the guard and types have to honor that.

But as you point out it the loss of precision is a potential problem. Is it feasible to make changes to vbank.go to always encode as string?

: yes, let's get it into u18a
  . make the change now
: yes, but not until u19
  . allow M.number() for now
  . put a P1 issue into u19 to use string encoding and remove the M.number()
: not anytime soon
  . allow M.number()
  . include ample documentation on the encoding and how we decided to leave it as is.

Let's discuss the trade-offs with other stakeholders.

@Chris-Hibbert
Copy link
Contributor

I'm also hitting this issue in cleaning up the upgrade 19 a3p-integration tests. If I change the guard from

  update: M.call(M.string()).optional(M.string()).returns(),

to

  update: M.call(M.string()).optional(M.or(M.string(), M.number())).returns(),

My problem goes away. I'll wait to see here what the correct solution is.

@turadg
Copy link
Member

turadg commented Feb 4, 2025

From discussion:

:- yes, let's get it into u18a
  . make the change now
  - the vat-bank in u18a ignores the nonce
:~ yes, but not until u19
  . allow M.number() for now
  . put a P1 issue into u19 to use string encoding and remove the M.number()
:+ not anytime soon
  + a 53-bit integer nonce will last for the forseeable future
  . allow M.number()
  . include ample documentation on the encoding and how we decided to leave it as is.

@Chris-Hibbert
Copy link
Contributor

What can I include in the update to upgrade-19 tests, which I'm working on now? I'd like this to be cleaned up before people want to start the release process for U19, which is supposed to follow close on the heels of U18a.

I currently have the guard allow M.or(M.string(), M.number()). Is there any problem with going forward with that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants