From 169fd2b23fcccdb46fb54be35e80ac0a4e62e837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Sat, 29 Jan 2022 08:34:16 +0100 Subject: [PATCH 1/4] Support for V1 contract state. --- haskell-src/Concordium/Wasm.hs | 48 +++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/haskell-src/Concordium/Wasm.hs b/haskell-src/Concordium/Wasm.hs index 54c76ef17..3d8904a02 100644 --- a/haskell-src/Concordium/Wasm.hs +++ b/haskell-src/Concordium/Wasm.hs @@ -104,7 +104,10 @@ module Concordium.Wasm ( SuccessfulResultData(..), getSuccessfulResultData, -- *** Failed execution - ContractExecutionFailure(..) + ContractExecutionFailure(..), + + -- |Instance queries + InstanceInfo(..) ) where import Control.Monad @@ -119,6 +122,7 @@ import Data.Char (isPunctuation, isAlphaNum, isAscii) import qualified Data.HashMap.Strict as HM import Data.Hashable import Data.Int (Int32) +import qualified Data.Set as Set import qualified Data.Map.Strict as Map import Data.Serialize import qualified Data.Text as Text @@ -666,3 +670,45 @@ data ContractExecutionFailure = ContractReject { rejectReason :: Int32 } -- ^Contract decided to terminate execution. | RuntimeFailure -- ^A trap was triggered. deriving(Eq, Show) + +-- |Data about the contract that is returned by a node query. +data InstanceInfo = InstanceInfoV0 { + iiModel :: !ContractState, + iiOwner :: !AccountAddress, + iiAmount :: !Amount, + iiMethods :: !(Set.Set ReceiveName), + iiName :: !InitName, + iiSourceModule :: !ModuleRef + } + | InstanceInfoV1 { + iiOwner :: !AccountAddress, + iiAmount :: !Amount, + iiMethods :: !(Set.Set ReceiveName), + iiName :: !InitName, + iiSourceModule :: !ModuleRef + } + +-- |Helper function for JSON encoding an 'Instance'. +instancePairs :: AE.KeyValue kv => InstanceInfo -> [kv] +{-# INLINE instancePairs #-} +instancePairs InstanceInfoV0{..} = + [ "model" AE..= iiModel, + "owner" AE..= iiOwner, + "amount" AE..= iiAmount, + "methods" AE..= iiMethods, + "name" AE..= iiName, + "sourceModule" AE..= iiSourceModule, + "version" AE..= V0 + ] +instancePairs InstanceInfoV1{..} = + [ "owner" AE..= iiOwner, + "amount" AE..= iiAmount, + "methods" AE..= iiMethods, + "name" AE..= iiName, + "sourceModule" AE..= iiSourceModule, + "version" AE..= V1 + ] + +instance AE.ToJSON InstanceInfo where + toJSON inst = AE.object $ instancePairs inst + toEncoding inst = AE.pairs $ mconcat $ instancePairs inst From 1efe6e3ee5674bf1a3bdf61a337525d6ea6ec2cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Sun, 6 Feb 2022 19:22:14 +0100 Subject: [PATCH 2/4] Auxliary function. --- haskell-src/Concordium/Wasm.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/haskell-src/Concordium/Wasm.hs b/haskell-src/Concordium/Wasm.hs index 3d8904a02..50f062a23 100644 --- a/haskell-src/Concordium/Wasm.hs +++ b/haskell-src/Concordium/Wasm.hs @@ -51,6 +51,7 @@ module Concordium.Wasm ( WasmModule(..), getModuleSource, getVersion, + demoteWasmVersion, WasmModuleV(..), getModuleRef, WasmVersion(..), @@ -192,6 +193,9 @@ instance IsWasmVersion 'V0 where instance IsWasmVersion 'V1 where getWasmVersion = SV1 +demoteWasmVersion :: SWasmVersion v -> WasmVersion +demoteWasmVersion SV0 = V0 +demoteWasmVersion SV1 = V1 -- | The source of a contract in binary wasm format. newtype ModuleSource (v :: WasmVersion) = ModuleSource { moduleSource :: ByteString } From e5292d81f9897b25217c2d1aba4b1d49939fd790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Wed, 2 Mar 2022 12:37:06 +0100 Subject: [PATCH 3/4] Add helper to construct fallback name. --- haskell-src/Concordium/Wasm.hs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/haskell-src/Concordium/Wasm.hs b/haskell-src/Concordium/Wasm.hs index aac9ae37b..ea7ab3be2 100644 --- a/haskell-src/Concordium/Wasm.hs +++ b/haskell-src/Concordium/Wasm.hs @@ -70,6 +70,7 @@ module Concordium.Wasm ( ReceiveName(..), isValidReceiveName, contractAndFunctionName, + makeFallbackReceiveName, extractInitReceiveNames, EntrypointName(..), isValidEntrypointName, @@ -414,6 +415,13 @@ extractInitReceiveNames nameText = do let cname = "init_" <> Text.takeWhile (/= '.') nameText return (InitName cname, ReceiveName nameText) +-- |Derive the name of a fallback entrypoint for the contract. +-- This is defined as the entrypoint "contractName.", i.e., with the empty function name. +makeFallbackReceiveName :: ReceiveName -> ReceiveName +makeFallbackReceiveName r = + let (cname, _) = contractAndFunctionName r + in ReceiveName (cname <> ".") + instance AE.FromJSON ReceiveName where parseJSON = AE.withText "ReceiveName" $ \receiveName -> do if isValidReceiveName receiveName then return ReceiveName{..} @@ -720,7 +728,7 @@ data InstanceInfo = InstanceInfoV0 { iiMethods :: !(Set.Set ReceiveName), iiName :: !InitName, iiSourceModule :: !ModuleRef - } + } deriving(Eq, Show) -- |Helper function for JSON encoding an 'Instance'. instancePairs :: AE.KeyValue kv => InstanceInfo -> [kv] From 9aa1993d149994f50fe3e0ccf4a4d8ca4151fe45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Fri, 11 Mar 2022 08:45:02 +0100 Subject: [PATCH 4/4] Documentation and missing instances. --- haskell-src/Concordium/Wasm.hs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/haskell-src/Concordium/Wasm.hs b/haskell-src/Concordium/Wasm.hs index ea7ab3be2..8f60e3ff6 100644 --- a/haskell-src/Concordium/Wasm.hs +++ b/haskell-src/Concordium/Wasm.hs @@ -465,6 +465,12 @@ newtype ContractState = ContractState {contractState :: BS.ByteString } instance AE.ToJSON ContractState where toJSON ContractState{..} = AE.String (Text.decodeUtf8 (BS16.encode contractState)) +instance AE.FromJSON ContractState where + parseJSON = AE.withText "ContractState" $ \csText -> + let (contractState, rest) = BS16.decode (Text.encodeUtf8 csText) + in if BS.null rest then return ContractState{..} + else fail "Invalid hex string." + -- The show instance just displays the bytes directly. instance Show ContractState where show ContractState{..} = show (BS.unpack contractState) @@ -713,7 +719,10 @@ data ContractExecutionFailure = | RuntimeFailure -- ^A trap was triggered. deriving(Eq, Show) --- |Data about the contract that is returned by a node query. +-- |Data about the contract that is returned by a node query. The V0 and V1 +-- instances are almost the same, but because the state of V1 instances is +-- unbounded in general, we cannot return it as such in queries. Thus there is +-- no "model" field for V1 instances. data InstanceInfo = InstanceInfoV0 { iiModel :: !ContractState, iiOwner :: !AccountAddress, @@ -730,7 +739,7 @@ data InstanceInfo = InstanceInfoV0 { iiSourceModule :: !ModuleRef } deriving(Eq, Show) --- |Helper function for JSON encoding an 'Instance'. +-- |Helper function for JSON encoding an 'InstanceInfo'. instancePairs :: AE.KeyValue kv => InstanceInfo -> [kv] {-# INLINE instancePairs #-} instancePairs InstanceInfoV0{..} = @@ -754,3 +763,16 @@ instancePairs InstanceInfoV1{..} = instance AE.ToJSON InstanceInfo where toJSON inst = AE.object $ instancePairs inst toEncoding inst = AE.pairs $ mconcat $ instancePairs inst + +instance AE.FromJSON InstanceInfo where + parseJSON = AE.withObject "InstanceInfo" $ \obj -> do + iiOwner <- obj AE..: "owner" + iiAmount <- obj AE..: "amount" + iiMethods <- obj AE..: "methods" + iiName <- obj AE..: "name" + iiSourceModule <- obj AE..: "sourceModule" + (obj AE..: "version") >>= \case + V0 -> do + iiModel <- obj AE..: "model" + return InstanceInfoV0{..} + V1 -> return InstanceInfoV1{..}