Support a mix of RPC and non-RPC representations in `runCode`
Clarification and motivation
in #737 (closed), we added support for the run_code
endpoint.
We were careful to make sure it supports passing the parameter/storage in either their RPC representation (with bigmap IDs) or their non-RPC representation (with bigmaps).
However, we didn't consider that a paramater/storage may contain a mix of both!
If a contract's parameter is of type pair (big_map int int) (big_map int int)
, the RPC allows us to pass it a Pair 4 {Elt 10 11}
(see repro below).
In fact, this is precisely what we need to do to implement the algorithm described at the bottom of #737 (closed).
The contract passed to runCode
will accept a pair pair $viewParam $contractStorage
, where $contractStorage
will contain bigmap IDs, and $viewParam
might contain either bigmaps or bigmap IDs.
We could fix the network implementation relatively easily: we change the RunCode
API to accept an untyped Value
instead, and let the RPC do all the hard work (though this is a bit of a cop out move
Fixing the emulator implementation is not so easy.
This requires more thought.
Repro
First, originate some contract with a bigmap in its storage in order to create a valid bigmap ID:
$ tezos-client originate contract test \
transferring 1 from baker \
running ./contracts/tezos_examples/opcodes/originate_big_map.tz --force \
--init '{Elt 10 11}' --burn-cap 1
The output should give us a valid bigmap ID:
Updated big_maps:
New map(4) of type (big_map int int)
Set map(4)[10] to 11
And then run the following Cleveland test (replacing 4
with whatever bigmap ID you got from the previous step):
import Lorentz
import Lorentz qualified as L
import Morley.Client
import Morley.Client.RPC as Client
import Morley.Micheline
import Test.Cleveland
import Test.Cleveland.Tasty
import Test.Tasty (TestTree)
import Test.Tasty.HUnit
test_repro :: TestTree
test_repro =
whenNetworkEnabled \withEnv -> do
testCase "repro" do
withEnv \env ->
runMorleyClientM (neMorleyClientEnv env) do
headConstants <- getBlockConstants HeadId
let mixedParam :: (BigMapId Integer Integer, BigMap Integer Integer) =
(4, one (10, 22))
res <- Client.runCode Client.RunCode
{ rcScript = toExpression testContract
, rcStorage = toExpression $ toVal @Integer 0
, rcInput = toExpression $ toVal mixedParam
, rcAmount = TezosMutez 0
, rcBalance = TezosMutez 0
, rcChainId = bcChainId headConstants
, rcSource = Nothing
, rcPayer = Nothing
}
print $ rcrStorage res
where
-- | Retrieves the value at index 10 from both bigmaps and adds the result together.
testContract :: Contract (BigMap Integer Integer, BigMap Integer Integer) Integer ()
testContract = defaultContract $
L.car
# L.unpair
-- get the value at index 10 from the first bigmap
# L.push @Integer 10
# L.get
# L.assertSome @MText "key not found"
-- get the value at index 10 from the second bigmap
# L.swap
# L.push @Integer 10
# L.get
# L.assertSome @MText "key not found"
-- add the two results together
# L.add
# L.nil @Operation # L.pair
Test's output:
ExpressionInt 33
Acceptance criteria
- The parameter/storage values passed to Cleveland & morley-client's
runCode
can be expressed with a mix of bigmaps and bigmap IDs.