I'm seeing issues using the update_current_contract_wasm host function. I just can't get it to work at all either locally or on network. I posted all the details I have about the issue here. https://github.com/stellar/rs-soroban-env/issues/1089
#How to update contract wasm?
95 messages · Page 1 of 1 (latest)
@past garden @hearty mango Is there something else we need to do when updating contract wasm to commit the change?
It just seems like the change isn't finalized/applied.
I see the system event indicating an upgrade is taking place:
{
"ext": "v0",
"contract_id": "da6f639880f9fad77bffc13d04bbafb27c6e7874650d0b305619cddcea017f59",
"type_": "system",
"body": {
"v0": {
"topics": [
{
"symbol": "executable_update"
},
{
"vec": [
{
"symbol": "Wasm"
},
{
"bytes": "bd661542ca3c05f673cdfc52cf8228be595328d313483c65573908e82ddda8ed"
}
]
},
{
"vec": [
{
"symbol": "Wasm"
},
{
"bytes": "a14c6e5275afb5faa17776bccf4b0b926dbb522e569f13a1b77f0b350e057392"
}
]
}
],
"data": {
"vec": []
}
}
}
}```
Is there something else we need to do when updating contract wasm to commit the change?
transaction has to succeed
but I guess if there is an event, it succeeded
why do you think it didn't succeed?
Because the updated contract is not callable.
When I invoke the contract I get old behavior.
I know for certain because my update adds a new function, and the new function isn't available.
My update also removes a function, but the old function is still available.
This is happening locally in Rust tests, and in the deployed network.
interesting, this seems like a regression to me. though IIRC there are tests that perform update and they still pass. is the LE not updated? do you have the full meta of the upgrade op?
(I mean the op that should've performed the updgrade)
Also, I saved the ledger state, and it's not changing.
The fully meta is at the link above.
hmm, meta has no change as well... I'll take a closer look
Meta does have the system event though, so it seems like it thinks it is succeeding, but something isn't sticking.
I'll push the contract to a repo so you can see what I'm doing, but it really is very lightweight, not much here.
I see there is some instance storage - my first suspect would be some bad override of the instance entry
ok
I'm deploying installer.wasm only, then calling its install function with no params. Then expecting to be able to call its deploy function.
Ah interesting. I can do a quick test to see what happens if I don't set instance storage. I'll just plop it in a temporary instead.
oh
yeah, I see the root of the issue
it's a pretty bad bug
good that you've found it
Ok yeah, when I change the storage type to something other than instance, the update works fine when deployed to network.
I think there's multiple issues here though. There's this issue with instance storage and updating which occurs on network. There's the original issue that in tests update doesn't work either, irrespective of storage type.
Yup, so when I use another storage type it is fixed.
Except in tests, it is still broken.
It seems like in tests that updates just never apply.
I understand the update shouldn't apply immediately because it has to take affect at the next ledger. But in tests we should probably have it apply (i.e. increment the ledger) after every top level invoke/frame is complete.
Just to pipe in with my observation, in the RPCiege challenge I am able to upgrade a deployed contract. In this case the upgraded contract has a function with the same name, just extra parameters. This is on futurenet
yeah, the bug has been there forever, yet just now we've got a combination of instance storage write+upgrade
The test issue I'm seeing might be different 🤔. I do see the ledger state changing when converting the ledger state to a snapshot.
do you upgrade a native contract to wasm?
My test is all wasms.
hmm
I have a test crate that tests the contracts in their wasm form only. No native test.
I'll look more then
Yeah in tests I'm getting a Error(WasmVm, UnexpectedType) when executing the upgraded contract, so it looks like the upgrade is working fine in tests when using another storage type.
I probably just have a logial bug in my contract.
I find the diagnostic events in tests very confusing in that the back trace includes every invoke in the test, rather than just the back trace for the last top-level invoke:
Event log (newest first):
0: [Diagnostic Event] topics:[error, Error(WasmVm, UnexpectedType)], data:"escalating error to panic"
1: [Diagnostic Event] topics:[error, Error(WasmVm, UnexpectedType)], data:["contract call failed", deploy, []]
2: [Diagnostic Event] topics:[fn_call, Bytes(05c2f5cc07cc3ffbf926de0afbecd09ebdc3cfeb359717ba8ec5a54461529a9d), deploy], data:Void
3: [Diagnostic Event] contract:05c2f5cc07cc3ffbf926de0afbecd09ebdc3cfeb359717ba8ec5a54461529a9d, topics:[fn_return, install], data:Void
4: [System Event] contract:05c2f5cc07cc3ffbf926de0afbecd09ebdc3cfeb359717ba8ec5a54461529a9d, topics:[executable_update, [Wasm, Bytes(b3c5eaa6e2e8718af8bd3a87f173669c42977acb3a492f82b65a0a2056a4d24e)], [Wasm, Bytes(b844d3ceac7c11f926c5b26ce2f65189f365c198b035f04d9e305768301ba009)]], data:[]
5: [Diagnostic Event] topics:[fn_call, Bytes(05c2f5cc07cc3ffbf926de0afbecd09ebdc3cfeb359717ba8ec5a54461529a9d), install], data:Void```
cc @jovial karma
that's because diagnostic events are not a backtrace...
I think it's possible to extract a backtrace from them though
Ok, the backtrace part of my message is a red herring.
(we would need to emit a diagnostic event for popping the stack frame though)
What I mean is each top-level invoke in a test is essentially its own tx, a new invoke into the system. So diagnostic logs shouldn't leak from one to the other.
ah, you mean at that level. yeah, we should flush them
FWIW I think we should flush everything - we do flush auth data, but nothing else
There's probably other things we should do like increment ledger number too.
like budget should be flushed as well
If someone needs to do testing as if it's inside a single contract call, they can wrap their calls with env.as_contract.
not sure for the ledger seq increment - you might want to simulate two txs in the same ledger
Good point.
@pale canopy I'm trying your test with my fix and it passes just fine. is there some other scenario that doesn't pass? I'll send a PR with the fix in the meantime
Is that testing it against a deployed network? Or in a local test?
I couldn't get the test to pass.
local test
Haha. Just discovered why my test was't passing. Writing to temporary, reading from instance 🤦🏻♂️
👍🏻 Sg.
hmm, I think there is another issue, which is that we always prioritize running the native contract implementation for an id
so updating native to wasm will work from the ledger standpoint, but calls would still lead to the native implementation
Hmm. We had tests in the SDK that exercised that behavior I thought.
did we? maybe I'm misreading the code then...
It should be possible to replace wasm with native, and native with wasm.
I'll probably address this separately anyway
Looking for the tests now...
not replace, but update
Maybe I just talked about writing the test...
using the env fn
register_test_.. should be covered indeed
hmm, there is some inherent ambiguity in native overrides
scenario A: you create a wasm contract using deployer host fns. then you register a native contract under the same id.
scenario B: you register a native contract. then you call update wasm host fn inside it
what should be the final value of contract executable in both scenarios? which implementation should we dispatch the calls to?
(FWIW we use a 'dummy' wasm executable for all the native contracts currently)
the issue is that I guess in scenario A you'd expect calls to be dispatched to native, while in B you'd expect calls to be dispatched to wasm. but that's not how things work now
If that's not how it works, that sounds like a bug.
It's reasonable for a user to expect the most recent update or registration to be the contract being executed.
yeah, so I think we should treat native contract registration in the same way as wasm update - it should reset executable to dummy value. then if we see the dummy executable we would dispatch to native implementation
also, given that the functionality of deployer host fns have been improved so much, I think we should consolidate the logic and leave only the native contract registration in host
ah, actually these aren't shared anyway, nvm
While on this thread, I was taking a look at this test implementation for deploying via wasm in soroban contracts https://github.com/stellar/soroban-examples/blob/f42ae737c349d1b0965560b1a65ca67cf695d04b/deployer/deployer/src/test.rs#L16
and wondering, what other ways can we reference a contract wasm apart from using the filesystem
example
- using a remote url
- using an already deployed contract wasm, by specifying it's hash or id
There have been ideas suggested in the past for doing something like this. For example: https://github.com/stellar/rs-soroban-sdk/issues/728
At the moment you must have it on the file system. You can get the contract wasm for any deployed contract by using the stellar contract fetch command.