-
Notifications
You must be signed in to change notification settings - Fork 364
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
test: unable to use std.AssertOriginCall
in _test
files
#481
Comments
Thank you @tbruyelle, I agree this is a bug and we should fix it. I think there are multiple ways to manage this case.
|
This could be basically handled by checking in the test helpers if the number of
So in this scenario we somehow manipulates
In this scenario we have 2 different test setups, one for If I understood correctly, the role of |
For 3, yes;
We can manipulate m.Frames, or maybe just regenerate a fresh context.
I mean adding new helpers that you can call when you're in the context of a unit test, so you can tell the VM to consider that the runtime is happening under certain conditions. We already have some test-specific Maybe we can add extend test-only helpers to play with the frames/stack.
Yep, there is room for improvement. As a contract developer, I want to be able to assert (non-exhaustive):
|
I have tested this "naive" change in pn.DefineNative("AssertOriginCall",
gno.Flds( // params
),
gno.Flds( // results
),
func(m *gno.Machine) {
- isOrigin := len(m.Frames) == 2
- if !isOrigin {
+ ctx := m.Context.(ExecContext)
+ if ctx.Msg == nil || len(ctx.Msg.GetSigners()) == 0 {
panic("invalid non-origin call")
}
},
) With that, we don't need any more to override the function for testing, if, in addition, we do the following change in func testMachineCustom(store gno.Store, pkgPath string, stdout io.Writer, maxAlloc int64, send std.Coins) *gno.Machine {
// FIXME: create a better package to manage this, with custom constructors
pkgAddr := gno.DerivePkgAddr(pkgPath) // the addr of the pkgPath called.
caller := gno.DerivePkgAddr(pkgPath) // NOTE: for the purpose of testing, the caller is generally the "main" package, same as pkgAddr.
pkgCoins := std.MustParseCoins("200000000ugnot").Add(send) // >= send.
banker := newTestBanker(pkgAddr.Bech32(), pkgCoins)
ctx := stdlibs.ExecContext{
ChainID: "dev",
Height: 123,
Timestamp: 1234567890,
- Msg: nil,
+ Msg: testutils.NewTestMsg(crypto.MustAddressFromString(caller.String())),
OrigCaller: caller.Bech32(),
OrigPkgAddr: pkgAddr.Bech32(),
OrigSend: send,
OrigSendSpent: new(std.Coins),
Banker: banker,
}
m := gno.NewMachineWithOptions(gno.MachineOptions{
PkgPath: "", // set later.
Output: stdout,
Store: store,
Context: ctx,
MaxAllocBytes: maxAlloc,
})
return m
} Which fills the signers of the message. Do you think it's acceptable ? |
It looks great 👍 I need to think about about the first snippet, about eventual edge cases. For the second snippet, I can't think any issue, only improvements. Please open a PR so we can continue the review and also rely on the CI to help us identify eventual edge cases. |
`AssertOriginCall` and `IsOriginCall` relies on the number of frames to determine if the function was called by a gno transaction (definition taken from `examples/gno.land/r/demo/banktest/README.md`). Since this number is different in the context of test and filetest, the 2 functions are overrided during test setup, but the override works only for filetest files and not for test files. This change makes `AssertOriginCall` and `IsOriginCall` to rely on message's signers instead of frames. If the message has at east one signer, we consider the function was called by a gno tx. As a result, the functions no longer needs to be overrided in test setup, and they work both for filetest files and test files. Fix gnolang#481
`AssertOriginCall` and `IsOriginCall` relies on the number of frames to determine if the function was called by a gno transaction (definition taken from `examples/gno.land/r/demo/banktest/README.md`). Since this number is different in the context of test and filetest, the 2 functions are overrided during test setup, but the override works only for filetest files and not for test files. This change makes `AssertOriginCall` and `IsOriginCall` to rely on message's signers instead of frames. If the message has at east one signer, we consider the function was called by a gno tx. As a result, the functions no longer needs to be overrided in test setup, and they work both for filetest files and test files. Fix gnolang#481
I really like this bug, or rather the discussion. That is,
But in my case; if I use then gnodev test pass, even when it's supposed to fail ( Edit: no it was me who didn't understand what a filetest was and how to use it. |
If you liked the discussion, please look at #495. |
Fix gnolang#481 `AssertOriginCall` and `IsOriginCall` functions can be used inside contracts to determine if the call comes directly from a tx (which is an *origin call*) or from an other contract (not an *origin call*). To do this those functions count the number of frames. In production environment, if there's exactly 2 frames, it is considered as an *origin call*. In test environment, the number of frames was 3, but it was working only for `_filetest`, and not for `_test`, where the setup is different and so the number of frames (7 instead of 3). To support `_test`, the change brings a way to identify if a test is a `_test` or `_filetest`, by checking the function name of the first frame. There's currently a pending discussion (gnolang#683) about how we should deal with frames, that's why I tried to keep this change minimal, but at least it fixes something and we can move forward. Ideally, `*OriginCall` functions should rely on something stronger that the number of frames, because for instance they could consider that a call is not an *origin call*, just because `std.IsOriginCall` is called by a sub-function of the same contract. But that's something we'll probably tackle with gnolang#683.
In test context,
std.AssertOriginCall
is overrided by the following code :Which works well for
_filetest
files, but not for_test
files because the number ofm.Frames
is not 3.I would like to make it compatible for both scenario, but for that I need to understand why checking the number of frames asserts that the caller is actually the signer of the tx. Any hint would be appreciated.
The frames for
_filetest
(dumped byspew.Dump()
) :The frames for
_test
:The text was updated successfully, but these errors were encountered: