Skip to content
This repository was archived by the owner on Apr 13, 2022. It is now read-only.

Commit a846116

Browse files
airvinnwaywood
andcommitted
Work in progress to refactor getStateByRange stub function
Co-authored-by: Nick Waywood <n.waywood@gmail.com> Signed-off-by: Allison Irvin <allison.irvin2@gmail.com>
1 parent e496b58 commit a846116

File tree

5 files changed

+67
-38
lines changed

5 files changed

+67
-38
lines changed

examples/Marbles.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{-# LANGUAGE DeriveGeneric #-}
33

44
-- Example invocations:
5+
-- peer chaincode instantiate -n mycc -v v0 -l golang -c '{"Args":["initMarble","marble1","red","large","Al"]}' -C myc -o orderer:7050
56
-- peer chaincode invoke -n mycc -c '{"Args":["initMarble","marble1","red","large","Al"]}' -C myc
67
-- peer chaincode invoke -n mycc -c '{"Args":["initMarble","marble2","blue","large","Nick"]}' -C myc
78
-- peer chaincode invoke -n mycc -c '{"Args":["readMarble","marble1"]}' -C myc

package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies:
2828
- containers
2929
- utf8-string
3030
- aeson
31+
- mtl
3132

3233
library:
3334
source-dirs:

src/Interfaces.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ class StateQueryIteratorInterface sqi where
7070
-- -- more elements in the collection key-value pairs returned by the result.
7171
hasNext :: sqi -> Bool
7272
-- -- close terminantes the iteration.
73-
close :: sqi -> Maybe Error
73+
close :: sqi -> IO (Maybe Error)
7474
-- -- Provides the next key-value pair pointed by the iterator
75-
next :: sqi -> Either Error Pb.KV
75+
next :: sqi -> IO (Either Error Pb.KV)
7676

7777
-- The type class HistoryQueryIterator defines the behaviour of the types that expose functionalities
7878
-- for iteratogin over a set of key modifications that are associated to the history of a key.

src/Stub.hs

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import Data.Vector as Vector
1616
, (!)
1717
)
1818
import qualified Data.ByteString.Lazy as LBS
19+
import Data.IORef (readIORef, newIORef, modifyIORef)
20+
import Control.Monad.Except (ExceptT(..), runExceptT)
1921

2022
import qualified Peer.ChaincodeShim as Pb
2123

@@ -111,27 +113,71 @@ instance ChaincodeStubInterface DefaultChaincodeStub where
111113
-- -- getStateValiationParameter :: ccs -> String -> Either Error [ByteString]
112114
-- getStateValiationParameter ccs key = Left notImplemented
113115
--
116+
117+
-- TODO: Implement better error handling/checks etc
114118
-- getStateByRange :: ccs -> Text -> Text -> IO (Either Error StateQueryIterator)
115119
getStateByRange ccs startKey endKey =
116120
let payload = getStateByRangePayload startKey endKey
117121
message = buildChaincodeMessage GET_STATE_BY_RANGE payload (txId ccs) (channelId ccs)
118-
bsToSqi :: ByteString -> Either Error StateQueryIterator
122+
-- We have listenForResponse a :: IO (Either Error ByteString)
123+
-- and the function bsToSqi :: ByteString -> IO (Either Error StateQueryIterator)
124+
-- And want IO (Either Error StateQueryIterator)
125+
-- ExceptT is a monad transformer that allows us to compose these by binding over IO Either
126+
bsToSqi :: ByteString -> ExceptT Error IO StateQueryIterator
119127
bsToSqi bs = let eeaQueryResponse = parse (decodeMessage (FieldNumber 1)) bs :: Either ParseError Pb.QueryResponse in
120128
case eeaQueryResponse of
121-
Left _ -> Left ParseError
122-
Right queryResponse -> Right StateQueryIterator {
123-
sqiChannelId = getChannelId ccs
124-
, sqiTxId = getTxId ccs
125-
, sqiResponse = queryResponse
126-
, sqiCurrentLoc = 0
127-
}
129+
Left _ -> ExceptT $ pure $ Left ParseError
130+
Right queryResponse -> ExceptT $ do
131+
-- queryResponse and currentLoc are IORefs as they need to be mutated
132+
-- as a part of the next() function
133+
queryResponseIORef <- newIORef queryResponse
134+
currentLocIORef <- newIORef 0
135+
pure $ Right StateQueryIterator {
136+
sqiChannelId = getChannelId ccs
137+
, sqiTxId = getTxId ccs
138+
, sqiResponse = queryResponseIORef
139+
, sqiCurrentLoc = currentLocIORef
140+
}
128141
in do
129142
e <- (sendStream ccs) message
130143
case e of
131144
Left err -> error ("Error while streaming: " ++ show err)
132145
Right _ -> pure ()
133-
(bsToSqi =<<) <$> listenForResponse (recvStream ccs)
146+
runExceptT $ ExceptT (listenForResponse (recvStream ccs)) >>= bsToSqi
147+
148+
-- TODO : implement all these interface functions
149+
instance StateQueryIteratorInterface StateQueryIterator where
150+
-- hasNext :: sqi -> Bool
151+
hasNext sqi = True
152+
-- close :: sqi -> IO (Maybe Error)
153+
close _ = pure Nothing
154+
-- next :: sqi -> IO (Either Error Pb.KV)
155+
next _ = pure $ Left $ Error "not implemented"
134156

157+
nextResult :: StateQueryIterator -> IO (Either Error Pb.QueryResultBytes)
158+
nextResult sqi = do
159+
currentLoc <- readIORef $ sqiCurrentLoc sqi
160+
queryResponse <- readIORef $ sqiResponse sqi
161+
-- Checking if there are more local results
162+
if (currentLoc < Prelude.length (Pb.queryResponseResults $ queryResponse)) then
163+
let queryResult = pure $ Right $ (Pb.queryResponseResults $ queryResponse) ! currentLoc in
164+
do
165+
modifyIORef (sqiCurrentLoc sqi) (+ 1)
166+
if ((currentLoc + 1) == Prelude.length (Pb.queryResponseResults $ queryResponse)) then
167+
do
168+
fetchNextQueryResult sqi
169+
queryResult
170+
else
171+
queryResult
172+
else pure $ Left $ Error "Invalid iterator state"
173+
174+
-- TODO : this function is only called when the local result list has been
175+
-- iterated through and there are more results to get from the peer
176+
-- It makes a call to get the next QueryResponse back from the peer
177+
-- and mutates the response with the new QueryResponse and set currentLoc back to 0
178+
fetchNextQueryResult :: StateQueryIterator -> IO (Either Error StateQueryIterator)
179+
fetchNextQueryResult sqi = pure $ Left $ Error "not yet implemented"
180+
135181
--
136182
-- -- getStateByRangeWithPagination :: ccs -> String -> String -> Int32 -> String -> Either Error (StateQueryIterator, Pb.QueryResponseMetadata)
137183
-- getStateByRangeWithPagination ccs startKey endKey pageSize bookmark = Left notImplemented
@@ -203,28 +249,4 @@ instance ChaincodeStubInterface DefaultChaincodeStub where
203249
-- getTxTimestamp ccs = Right txTimestamp
204250
--
205251
-- -- setEvent :: ccs -> String -> ByteArray -> Maybe Error
206-
-- setEvent ccs = Right notImplemented
207-
208-
instance StateQueryIteratorInterface StateQueryIterator where
209-
-- hasNext :: sqi -> Bool
210-
hasNext sqi = True
211-
-- close :: sqi -> Maybe Error
212-
close _ = Nothing
213-
-- next :: sqi -> Either Error Pb.KV
214-
next _ = Left $ Error "not implemented"
215-
216-
nextResult :: StateQueryIterator -> IO (Either Error Pb.QueryResultBytes)
217-
nextResult sqi = let x = _one =<< (fetchNextQueryResult sqi) in _two
218-
-- if (sqiCurrentLoc sqi) < Prelude.length (Pb.queryResponseResults $ sqiResponse sqi) then
219-
-- pure $ Right $ (Pb.queryResponseResults $ sqiResponse sqi) ! (sqiCurrentLoc sqi)
220-
-- else pure $ Left $ Error "what"
221-
-- if Pb.queryResponseHasMore $ sqiResponse sqi then
222-
-- x
223-
-- -- (nextResult =<<) =<< (fetchNextQueryResult sqi)
224-
-- -- _ <$> (fetchNextQueryResult sqi)
225-
-- else pure $ Left $ Error "Error retrieving next queryResult"
226-
227-
228-
-- x = fetchNextQueryResult sqi >>= (\eeSqi -> pure $ eeSqi >>= (\a -> pure $ nextResult a))
229-
fetchNextQueryResult :: StateQueryIterator -> IO (Either Error StateQueryIterator)
230-
fetchNextQueryResult sqi = pure $ Left $ Error "not yet implemented"
252+
-- setEvent ccs = Right notImplemented

src/Types.hs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Data.ByteString
44
import Data.Map
55
import Data.Vector
66
import Data.Text
7+
import Data.IORef
8+
import System.IO.Unsafe
79

810
import Network.GRPC.HighLevel.Generated
911
import Proto3.Suite
@@ -58,10 +60,13 @@ data DefaultChaincodeStub = DefaultChaincodeStub {
5860
data StateQueryIterator = StateQueryIterator {
5961
sqiChannelId :: Text,
6062
sqiTxId :: Text,
61-
sqiResponse :: Pb.QueryResponse,
62-
sqiCurrentLoc :: Int
63+
sqiResponse :: IORef Pb.QueryResponse,
64+
sqiCurrentLoc :: IORef Int
6365
} deriving (Show)
6466

67+
instance (Show a) => Show (IORef a) where
68+
show a = show (unsafePerformIO (readIORef a))
69+
6570
-- MapStringBytes is a synonym for the Map type whose keys are String and values
6671
type MapStringBytes = Map String ByteString
6772

0 commit comments

Comments
 (0)