#Is it possible to configure custom limits for the standalone quickstart?
165 messages · Page 1 of 1 (latest)
Generally it would be really nice to have more profiling insight into budget spends on "actual" networks vs Rust tests
yes and no - you can perform a network upgrade and we even have a script for that, but I'm not sure how easy it would be to execute with quickstart
it would be great if you could hack it for quickstart
Are these accurate for Phase 1?
https://github.com/stellar/stellar-core/blob/f88cf99d09a01355bf7335a02f1358170bc26527/scripts/soroban-settings/SorobanSettingsUpgrade.py#L35-L43
(actually, seems like there is some commented-out code for standalone as well)
yes, that's what has been used for the upgrade
I'm also guessing currently there's no real way to see how any given invocation stacked up against these values in case of simulation failure correct?
Would be nice if standalone had a just force it through to see where you limits will/did exceed
Standalone alrady has the high limit override enabled, so it should have much higher limits than testnet.
@royal mason quickstart standalone != stellar-core standalone.
simulation will need some limits, as its a sandbox and it shouldn't run arbitrarily large programs. but it could be somewhat larger than mainnet
oh, what is it then?
This is why we renamed quickstart standalone recently to "local".
Quickstart local is just a local network running with mostly same config as testnet, except accelerated, and high limit override is enabled.
orly!
Once https://github.com/stellar/stellar-core/issues/3863 is done, I think we should abandon the high limit override and allow configuring your own limits in quickstart.
I think high core limit overrides help much though (if anything, these can be somewhat confusing). simulation overrides seem much more useful
Ultimately looking for the "official" way to test contracts when you're getting errors like this
host invocation failed\n\nCaused by:\n HostError: Error(Budget, ExceededLimit)\n DebugInfo not available\n
IDK if we enable/collect debug events in standalone quickstart... but we should
Probably in a rust test. Load the wasm, set unlimited budget.
Then review the budget and see what is big.
BTW this is an execution error, which means that you've exceeded the limit you've set in tx
Which probably means it is a simulation bug.
(we need some debug guide for the errors... I know it's confusing)
I'm seeing pretty significant differences between testing in Rust and testing on a network
Even when testing against compiled WASM
that's concerning
This also won't throw if you go beyond limits like max_read_entries_tx or max_write_entries_per_tx
preflight adds about 15% on top of the simulated instructions, so we should hopefully be reasonably safe. but could you quantify 'significant'?
When you say different, do you mean different to what's actually required, or different to what preflight is saying you need?
Latter. What preflight says is needed vs what Rust test says was used. Trying to get some concrete values. My contracts is…slow
I may have been lying
Rust test
Cpu limit: 18446744073709551615; used: 22852853
Mem limit: 18446744073709551615; used: 3425979
Simulation
"cost": {
"cpuInsns": "24379542",
"memBytes": "3405269"
},
as I've mentioned above, simulation is expected to return higher values than the tests because it just adds some percentage on top of simulated values in order to account for metering divergence and possible ledger state changes
(metering divergence due to recording storage and recording auth, that is)
Rust test is prob correct on cpuinsns?
it has the same divergence issues. the only way to be correct (for a given ledger state) is to build a full transaction and run it in the enforcing mode (which isn't feasible in tests and still won't necesserily reflect the reality where e.g. more signatures are used for multisig)
but it should be close enough
Same invocation but with higher resource consumption
Rust test
Cpu limit: 18446744073709551615; used: 47684029
Mem limit: 18446744073709551615; used: 18138765
Simulation
"cost": {
"cpuInsns": "31068040",
"memBytes": "8962315"
},
Seems like significant divergence to me. Especially given the test is actually trending higher
You need to reset the budget after each run in a test, otherwise it accumulates.
I'm doing this
env.budget().reset_unlimited();
let id = client
.glyph_mint(&u1_address, &None, &map![&env], &Some(width as u32))
.unwrap();
env.budget().print();
Doing
let map = map![&env];
env.budget().reset_unlimited();
let id = client
.glyph_mint(&u1_address, &None, &map, &Some(width as u32))
.unwrap();
env.budget().print();
Makes a very marginal difference from 67665746 to 67664478 cpu and 39437229 to 39437165. I'm still seeing roughly 10M more CPU and 1M MEM used on the actual network vs the Rust test side.
fwiw I'm sending quite a number of events in this invocation and interacting with storage and a SAC token as well
That was a lie the smaller numbers are on the Rust test side NOT the network side. (I corrected my statement above)
I'm also noticing my CPU result fluctuates running the same test in Rust. Which seems odd?
That seems odd.
The only randomness are my Address. Unless env.crypto().sha256 has some randomness as well, which I would doubt
Sha256 shouldn't have any randomness. The system should be entirely reproducible, and not being reproducible would be a bug.
Even the prng is seeded in tests with a fixed reproducible seed. The only thing that's random is Addresses are randomly generated, but that shouldn't cause any cost difference.
@pliant light is it possible to extend the expiration defaults for local? It's very short atm
@somber marsh could we make all the limits configurable? Maybe instead of the high limit being a Boolean, it could be a toml section letting us set every parameter including expiration?
Or is this something we'd be able to do if we used the upgrade?
We could, but there would be ~20 values to override so it would get messy just for testing. The upgrade mechanism is the right way to do this, but we need to add some tooling to make it easier to use.
I might be missing something, but it seems to me like the issues that are being discussed here happen due to exceeding tx limits, not network limits. i.e. it has nothing to do with the network limit overrides.
20 is a small number. Is this an issue of technical debt with how core manages config? I thought core's config is just toml. If we add a toml section, the 20 configs can live under a section and do not need to be top-level soup.
I agree upgrades would be better, mostly because we could even support changing the limits in the quickstart local network while the network is running without having to restart. But improving upgrades seem to be a ways off.
again, could you please clarify the reason for configuring these limits?
in my mind there are only a few valuable setups: high limits on everything, matching mainnet, matching testnet. why should one ever need to e.g. raise the memory limit, but nothing else? the tx will still fail on the relevant network and network limit enforcement is really trivial to reproduce off-chain when necessary (e.g. in preflight)
Running transaction against an actual network is very valuable when you can't check valid limits in Rust tests and returned errors on actual networks don't tell you what or by how much you exceeded a limit
Main reasons is to match a network, or raise limits to unlimited.
right, that matches my intuition. but matching network is inconvenient to achieve via toml config and for high limits we already have a flag, don't we?
FWIW 'matching the network' is more involved than matching the limits. you'll also probably want to have the same fees and the same budget calibration
High limits just sets a little bit high. Also when we add features that are bespoke to testing, we end up with bugs like what happened for the last two weeks where it didn't work the same as a network and was buggy. Since upgrade config is something that already exists, seems reasons to rely on that existing behavior and it's maximally flexible.
I tottally agree here, which is why I don't want to add more test-only flags to core (which seems to be the suggestion here?). I want to off-load this to the upgrade script
I'm honestly slightly indifferent as long as it's simple for devs. I will say the local quickstart is a bit handicapped with things expiring in what I feel like is 30 minutes
hmm, I think that's useful - you probably should bump your entries. we could of course add an option to increase the default lifetime significantly for the local instances, but really we're not quite building a sandbox here - the end goal of the contract development is the mainnet deployment and you do need to worry about lifetimes
30 minutes is painful for local. It should be easily configurable
Both lower and higher
lower - maybe, higher - why? it probably matches mainnet, but it's 5x faster due to faster ledger closing. again, you should probably be bumping your entries, so I'm not sure if that's a 'bug' or a 'feature'
Mainnet is going to be 30 minutes? 😳
For local it's absolutely a bug or a missing feature at least
local should let you pretty much do whatever with fees and limits
I should be able to isolate the interest I want to currently test against, for me right now that's fees and metering, but if I keep hitting expired entries every 30 minutes that's very frustrating. I'll deal with bumping later.
it's 4096 ledgers, so whatever time it takes to apply that many ledgers (about 6 hours)
I'm pretty sure local is closing ledgers like every second
It's definitely not taking 6 hours before my entries are expiring
I should be able to isolate the interest I want to currently test against,
again, I'm not strictly opposed to making these modifiable. however, I'm not sure if that's the right development philosophy in general and I'm not sure it should be promoted. I'd hope most of the things are achievable within the unit testing framework and you'd go to the local network to figure out the tx side of the interactions
again, it's 4096 ledgers. so it's about 5x slower on the real network, so this works as expected. we can bump the limit 5x on local node. but the entries will still expire soon enough if you don't bump them
most of the things
Well they aren't right now. Many of the fees are not easily accounted for currently, if we can fix that then sure
basically if you're running the WIP contracts against the localnet, then it's likely because we have gaps in the testing infra. I wonder what these gaps are
30-60 minutes vs 6 hours is a big difference. And imo for local this should be at least 1 full day
It's a dev environment, if I wanted to test the prod I'd run on prod
Again though it should just be configurable, even if my a script vs toml configurations
but the bump is a part of your contract logic, isn't it?
For instance entries sure but not permanent ones no
why?
imagine you have a token contract and your balance expire within 5 hours. would it be a good UX for your users?
I don't want to? idk, I'm not testing that piece right now. I want to do that in a separate Stellar transaction later? It shouldn't matter. I should be able to test in a local env the specific part of my contract without having to worry about specific network configurations. Again local is already very close with this by allow much larger limits
my point here is rather not that you should/shouldn't be able to do something, but more so about flagging the state archival. unlike common stuff, like instructions/gas, this might be not and immediately obvious concept. I'm a bit concerned about hiding it completely during the development process only to make it blow up during the release
What we have now is a weird build the whole thing for prod before you test any piece of it but then when things start to break it's quite tricky to find where it broke
We need to be able to build and test incrementally separate parts of the contract without having to care about every other piece
things start to break it's quite tricky to find where it broke
yes, that definitely sucks - we need to do better on the preflight side
We may ultimately be saying the same thing but where you care more about archives I currently care more about fees
The difference is archieves actually have some tooling to be able to recoup in case you mucked up. Restore, bump, etc. But if you mucked up on fees, your just stuck, so that is far more concerning to me right now
Especially because you can't appropriate test to find these issues
FWIW bumps are not free
Sure, but you can do them without the need to call the contract, so you contract isn't bricked
You can very easily brick a contract right now if you don't get your fees right
And there's not clear way to test what fees you're using or hitting outside of just raw CPU and MEM
ok, noted - besides the limit tweaking let's really get down to the fee issues you have
In a nutshell it's easily measuring these 👆
- First in a Rust test
- And in a simulation
CPU and RAM we have via env.budget().print(); though as I've noted I'm not finding these to be terribly accurate to the actual network
But for the rest we really have nothing as if you go over during sim it just errors with unhelpful messages
yes, that's fair
tx size is tricky to do in tests. everything else can actually be computed
The workaround I'm using is testing in local which doesn't adhere to these limits and lets you go over (avoiding the error) and then you can check the response against this table to see where you've gone over
(with a caveat of not having the real ledger state- but the same is true for local network as well)
See my sorobill tool here #1161385760902103100 message
That would be awesome
I've never found tx size to be an actual issue except when actually installing the contract. For normal fn invokes it's always under this. Unless I guess an argument is REALLY big
Which again the sim side of testing would catch even if the Rust test couldn't
yes, that's why I'm not that concerned about it
For example prior to 20-rc I was emitting a bunch of events. This 2 kb limit crushed my contracts. And I had no idea how to surface that. Until I ran in local then boom. I saw my events sum was well over 2 KB
FWIW 2KB limit can be increased
that's unfortunately the first time someone complained about it
The point is less that it's a problem, I may be an outlier (though 2kb is really limited)
The point for now is I had no clear avenue for how to find the source of the exceededLimit simulation error
(I'll open a separate issue for the 2kb limit to discuss)
The point for now is I had no clear avenue for how to find the source of the exceededLimit simulation error
we need a separate issue for that as well. I think that just returning the diagnostic events could solve this
Is that a soroban-tools issue? Happy to open one unless you've got a better sense what should go into that
yes, it might need some env-side support, but I think plumbing the events (or at least the last diagnostic event that contains the error) should help with this
Events are already accessible in tests. Is that what you're needing?
The size of the events as metered by the limits table is what I'm needing
we need to a) reset events for every invocation (I think there is a separate issue for that) and b) add a getter for encoded events size
Along with all the other limits as well. Ideally all collected back into the budget tool we already have
b) should also filter out diagnostic events
I didn't keep up with the thread because I had to go AFK. If we can make config updates easier to do I can incorporate them into quickstart so we can configure whatever we need on the quickstart side. If we can move away from bespoke testing functionality would be awesome, so we don't need core builds to tweak things.
Want me to take a stab at stubbing out an issue for this?
yeah, please open an issue for soroban-tools, thanks
event observation is useful for testing the logic, but we also need a simple way to check the size. the same goes about storage - there is a way to see what's stored, but that's not convenient for verifying the total IO consumption
There are currently quite a number or fees and limits for Soroban transaction submission https://soroban.stellar.org/docs/fundamentals-and-concepts/fees-and-metering#resource-limits A transaction c...
@gentle bluff Would it makes sense in your mind to disable expiration limits for local by default (or set them so high no typical developer would encount an expired entry), and provide an option to enable expiration so that developers can test with expiration when they're ready.
Reading the comments I'm getting a sense that folks are encountering expiration before they're ready, or maybe when it is irrelevant.
In my own experience when I'm focused on contract development I don't care about expiration because for the most part it just results in me having to stop what I'm doing and run extra commands. When I'm focused on client/dapp development I do get to a point where I care about expiration because I want to make sure the wallet or application I'm developing knows how to restore.
I'm getting a sense that folks are encountering expiration before they're ready,
ugh, I guess it's nice to help with on-boarding... but I feel like it would be more productive to highlight this to the devs as soon as possible - it's really easy to miss expiration in the SDK and then if you make it easy in local it could result in devs wasting time building something that is not compatible with state archival. disabling expiration should at least be a conscious choice IMHO...
building something that is not compatible with state archival
What are some examples of something that is not compatible?
Well not bumping in your contract anywhere would be an example.
But yeah I would like an opt out of expiration flag for sure
But that isn't a compatibility issue. You can restore, the expiration isn't destructive.
it's pretty easy to shoot yourself in a leg with temp entries
Incompatibility would mean your contract is entirely broken, or just won't work.
Temp entries are a good example of why we should keep expiration on.
also just thinking about user flows - while everything is possible to do in theory, in practice owner-less protocols need to think about how they maintain their state. maybe it's not strictly 'incompatible' but I can imagine certain design approaches being less feasible given the existence of state archival
What's an example of that?
basically anything with cold storage + no ownership might be tricky. I don't have a specific example though
I'm just wanting to get my mind seeing the same scenarios.
Either way I think it’s the more rare case especially early in the dev cycle/journey so having hard mode on by default feels wrong
Can the default expiration of temp entries and persistent entries be set separately?
again, I'm not opposed to maybe not disabling the state archival completely (that would require too much core hacking), but at least setting arbitrarily large min expiration such that it's not noticeable unless you develop your contract for years. I just don't want to make it default and hide state archival completely
yes
it is in fact different
We could benefit from temp entries expire, persistent entries don't.
yeah, we could set persistent to be 10 years in the future
Then include an option on quickstart --enable-state-archival.
To reduce persistent down to something shorter.
yeah
Once we can configure things we can let people set the vaue instead of being a boolean.
btw with new terminology ('state archival') we can really only apply it to persistent entries, because temp entries are not archived
That's perfect.
so I think state archival implies persistent anyway. and temp entries are just temporary - I think it's a well understood concept and there shouldn't be an issue with temp entries being gone forever
To make this happen, is the right thing to add a new config to stellar-core, or hang tight for the new config updater tool and we'll use that in quickstart?
if this requires a new core build, I'd say let's do the proper (update) thing. there is a bunch of stuff to merge in core and I don't think we have much time for test-only settings