Open cthulhu-rider opened 1 year ago
Changing contract on the fly is not a good idea, we're supposed to compile/deploy them exactly. Currently it's possible to use custom stores for chain.NewSingleWithCustomConfigAndStore()
and chain.NewMultiWithCustomConfigAndStore
where you have a complete storage API (seems like you're already doing it). But as you know underlying store may be a bit outdated compared to the internal Blockchain
memory cache. Blockchain
is specifically designed to never expose its memcache/DAO, but we may think about some specific hooks for tests, that I think will be safer and more appropriate way to handle this problem.
think about some specific hooks for tests
Ofc test hooks in core lib would be much better than contract surgery.
Here's a workaround suggested by @roman-khimov for the case here when you just want to add contract with some data in advance.
lowLevelStore := storage.NewMemoryStore()
_dao := dao.NewSimple(lowLevelStore, false, true)
nativeContracts := native.NewContracts(config.ProtocolConfiguration{})
err := nativeContracts.Management.InitializeCache(_dao)
require.NoError(tb, err)
err = native.PutContractState(_dao, &_state)
require.NoError(tb, err)
// store values in lowLevelStore
_, err = _dao.PersistSync()
_, err = cachedStore.PersistSync()
// init blockchain
useDefaultConfig := func(*config.Blockchain) {}
blockChain, alphabetSigner := chain.NewSingleWithCustomConfigAndStore(tb, useDefaultConfig, lowLevelStore, true)
However, it is worth noting that after that contract invocations fail with contract not found
exceptions. https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/core#Blockchain.GetContractState returns nil
, but https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/core#Blockchain.GetContractScriptHash works.
Please try
blockChain, _ := chain.NewSingleWithCustomConfigAndStore(tb, useDefaultConfig, lowLevelStore, true)
blockChain.Close()
blockChain, alphabetSigner := chain.NewSingleWithCustomConfigAndStore(tb, useDefaultConfig, lowLevelStore, true)
Yeah, it's weird. But otherwise management contract's cache is not really initialized, because we're starting with an (almost) clean DB, it's inited for the genesis and that's it.
Please try
It really works. The only thing I also needed to do is to make no-op Close
method of the storage.Store
passed on the first init. Without this, blockChain.Close
reset underlying maps.
Context
I try to test migration of contracts' storage items using framework provided by
neotest
package. Sometimes contract stores items within its methods, so technically I could just call exact method. The inconvenience is that such elements are stored in the contract as a result of API methods that are not always easy to call within the test due to the need to follow business logic. At the same time, I did not find other ways.Proposal
Add functionality to
neotest
package which allows to directly write key-value item into the contract storage.Possible solution
The least affecting approach I thought about is to add analogue of https://pkg.go.dev/github.com/nspcc-dev/neo-go@v0.101.0/pkg/neotest#CompileFile
which, after reading the source code of the contract (but before compiling), adds direct-write method for the life of the test contract. You can call this method later like any other one.