Skip to content
This repository was archived by the owner on Aug 18, 2020. It is now read-only.

added unspent transaction outputs endpoint to explorer #3324

Merged
merged 2 commits into from
Jul 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions explorer/src/Pos/Explorer/Aeson/ClientTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import Data.Fixed (showFixed)

import Pos.Explorer.Web.ClientTypes (CAda (..), CAddress,
CAddressSummary, CAddressType, CBlockEntry, CBlockSummary,
CCoin, CGenesisAddressInfo, CGenesisSummary, CHash,
CNetworkAddress, CTxBrief, CTxEntry, CTxId, CTxSummary)
CByteString (..), CCoin, CGenesisAddressInfo,
CGenesisSummary, CHash, CNetworkAddress, CTxBrief,
CTxEntry, CTxId, CTxSummary, CUtxo)
import Pos.Explorer.Web.Error (ExplorerError)

deriveJSON defaultOptions ''CHash
Expand All @@ -37,6 +38,10 @@ deriveToJSON defaultOptions ''CNetworkAddress
deriveToJSON defaultOptions ''CTxSummary
deriveToJSON defaultOptions ''CGenesisSummary
deriveToJSON defaultOptions ''CGenesisAddressInfo
deriveToJSON defaultOptions ''CUtxo

instance ToJSON CByteString where
toJSON (CByteString bs) = (toJSON.toString) bs

instance ToJSON CAda where
-- https://github.com/bos/aeson/issues/227#issuecomment-245400284
Expand Down
13 changes: 11 additions & 2 deletions explorer/src/Pos/Explorer/Web/Api.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ import Universum

import Control.Exception.Safe (try)
import Data.Proxy (Proxy (Proxy))
import Servant.API ((:>), Capture, Get, JSON, QueryParam, Summary)
import Servant.API ((:>), Capture, Get, JSON, Post, QueryParam,
ReqBody, Summary)
import Servant.Generic ((:-), AsApi, ToServant)
import Servant.Server (ServantErr (..))

import Pos.Core (EpochIndex)
import Pos.Explorer.Web.ClientTypes (Byte, CAda, CAddress,
CAddressSummary, CAddressesFilter, CBlockEntry,
CBlockSummary, CGenesisAddressInfo, CGenesisSummary,
CHash, CTxBrief, CTxEntry, CTxId, CTxSummary)
CHash, CTxBrief, CTxEntry, CTxId, CTxSummary, CUtxo)
import Pos.Explorer.Web.Error (ExplorerError)
import Pos.Util.Servant (DQueryParam, ModifiesApiRes (..), VerbMod)

Expand Down Expand Up @@ -114,6 +115,14 @@ data ExplorerApiRecord route = ExplorerApiRecord
:> Capture "address" CAddress
:> ExRes Get CAddressSummary

, _addressUtxoBulk :: route
:- Summary "Get summary information about multiple addresses."
:> "bulk"
:> "addresses"
:> "utxo"
:> ReqBody '[JSON] [CAddress]
:> ExRes Post [CUtxo]

, _epochPages :: route
:- Summary "Get epoch pages, all the paged slots in the epoch."
:> "epochs"
Expand Down
22 changes: 22 additions & 0 deletions explorer/src/Pos/Explorer/Web/ClientTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module Pos.Explorer.Web.ClientTypes
, CAddressType (..)
, CAddressSummary (..)
, CTxBrief (..)
, CUtxo (..)
, CNetworkAddress (..)
, CTxSummary (..)
, CGenesisSummary (..)
Expand All @@ -29,6 +30,7 @@ module Pos.Explorer.Web.ClientTypes
, LocalSlotIndex (..)
, StakeholderId
, Byte
, CByteString (..)
, mkCCoin
, mkCCoinMB
, toCHash
Expand Down Expand Up @@ -87,6 +89,8 @@ import Pos.Explorer.Core (TxExtra (..))
import Pos.Explorer.ExplorerMode (ExplorerMode)
import Pos.Explorer.ExtraContext (HasExplorerCSLInterface (..))
import Pos.Explorer.TestUtil (secretKeyToAddress)


-------------------------------------------------------------------------------------
-- Hash types
-------------------------------------------------------------------------------------
Expand Down Expand Up @@ -308,6 +312,18 @@ data CTxBrief = CTxBrief
, ctbOutputSum :: !CCoin
} deriving (Show, Generic)

data CUtxo = CUtxo
{ cuId :: !CTxId
, cuOutIndex :: !Int
, cuAddress :: !CAddress
, cuCoins :: !CCoin
}
| CUtxoUnknown
{ cuTag :: !Int
, cuBs :: !CByteString
}
deriving (Show, Generic)

newtype CNetworkAddress = CNetworkAddress Text
deriving (Show, Generic)

Expand Down Expand Up @@ -431,6 +447,12 @@ sumCoinOfInputsOutputs addressListMB
mkCCoin $ mkCoin $ fromIntegral $ sum addressCoinList
| otherwise = mkCCoinMB Nothing

newtype CByteString = CByteString ByteString
deriving (Generic)

instance Show CByteString where
show (CByteString bs) = (show . toString) bs

--------------------------------------------------------------------------------
-- Arbitrary instances
--------------------------------------------------------------------------------
Expand Down
65 changes: 53 additions & 12 deletions explorer/src/Pos/Explorer/Web/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ import Network.Wai.Middleware.RequestLogger (logStdoutDev)

import qualified Serokell.Util.Base64 as B64
import Servant.Generic (AsServerT, toServant)
import Servant.Server (Server, ServerT, serve)
import Servant.Server (Server, ServerT, err405, errReasonPhrase,
serve)
import System.Wlog (logDebug)

import Pos.Crypto (WithHash (..), hash, redeemPkBuild, withHash)
Expand All @@ -65,10 +66,10 @@ import Pos.Core (AddrType (..), Address (..), Coin, EpochIndex,
import Pos.Core.Block (Block, HeaderHash, MainBlock, gbHeader,
gbhConsensus, mainBlockSlot, mainBlockTxPayload, mcdSlot)
import Pos.Core.Chrono (NewestFirst (..))
import Pos.Core.Txp (Tx (..), TxAux, TxId, TxOutAux (..), taTx,
txOutValue, txpTxs, _txOutputs)
import Pos.DB.Txp (MonadTxpMem, getLocalTxs, getMemPool,
withTxpLocalData)
import Pos.Core.Txp (Tx (..), TxAux, TxId, TxIn (..), TxOutAux (..),
taTx, txOutAddress, txOutValue, txpTxs, _txOutputs)
import Pos.DB.Txp (MonadTxpMem, getFilteredUtxo, getLocalTxs,
getMemPool, withTxpLocalData)
import Pos.Infra.Slotting (MonadSlots (..), getSlotStart)
import Pos.Util (divRoundUp, maybeThrow)
import Pos.Web (serveImpl)
Expand All @@ -86,15 +87,18 @@ import Pos.Explorer.Web.Api (ExplorerApi, ExplorerApiRecord (..),
import Pos.Explorer.Web.ClientTypes (Byte, CAda (..), CAddress (..),
CAddressSummary (..), CAddressType (..),
CAddressesFilter (..), CBlockEntry (..),
CBlockSummary (..), CGenesisAddressInfo (..),
CGenesisSummary (..), CHash, CTxBrief (..), CTxEntry (..),
CTxId (..), CTxSummary (..), TxInternal (..),
convertTxOutputs, convertTxOutputsMB, fromCAddress,
fromCHash, fromCTxId, getEpochIndex, getSlotIndex,
mkCCoin, mkCCoinMB, tiToTxEntry, toBlockEntry,
toBlockSummary, toCAddress, toCHash, toCTxId, toTxBrief)
CBlockSummary (..), CByteString (..),
CGenesisAddressInfo (..), CGenesisSummary (..), CHash,
CTxBrief (..), CTxEntry (..), CTxId (..), CTxSummary (..),
CUtxo (..), TxInternal (..), convertTxOutputs,
convertTxOutputsMB, fromCAddress, fromCHash, fromCTxId,
getEpochIndex, getSlotIndex, mkCCoin, mkCCoinMB,
tiToTxEntry, toBlockEntry, toBlockSummary, toCAddress,
toCHash, toCTxId, toTxBrief)
import Pos.Explorer.Web.Error (ExplorerError (..))

import qualified Data.Map as M
import Pos.Configuration (explorerExtendedApi)


----------------------------------------------------------------
Expand Down Expand Up @@ -132,6 +136,7 @@ explorerHandlers _diffusion =
, _txsLast = getLastTxs
, _txsSummary = getTxSummary
, _addressSummary = getAddressSummary
, _addressUtxoBulk = getAddressUtxoBulk
, _epochPages = getEpochPage
, _epochSlots = getEpochSlot
, _genesisSummary = getGenesisSummary
Expand Down Expand Up @@ -371,6 +376,42 @@ getAddressSummary cAddr = do
ATRedeem -> CRedeemAddress
ATUnknown {} -> CUnknownAddress


getAddressUtxoBulk
:: (ExplorerMode ctx m)
=> [CAddress]
-> m [CUtxo]
getAddressUtxoBulk cAddrs = do
unless explorerExtendedApi $
throwM err405
{ errReasonPhrase = "Explorer extended API is disabled by configuration!"
}

let nAddrs = length cAddrs

when (nAddrs > 10) $
throwM err405
{ errReasonPhrase = "Maximum number of addresses you can send to fetch Utxo in bulk is 10!"
}

addrs <- mapM cAddrToAddr cAddrs
utxo <- getFilteredUtxo addrs

pure . map futxoToCUtxo . M.toList $ utxo
where
futxoToCUtxo :: (TxIn, TxOutAux) -> CUtxo
futxoToCUtxo ((TxInUtxo txInHash txInIndex), txOutAux) = CUtxo {
cuId = toCTxId txInHash,
cuOutIndex = fromIntegral txInIndex,
cuAddress = toCAddress . txOutAddress . toaOut $ txOutAux,
cuCoins = mkCCoin . txOutValue . toaOut $ txOutAux
}
futxoToCUtxo ((TxInUnknown tag bs), _) = CUtxoUnknown {
cuTag = fromIntegral tag,
cuBs = CByteString bs
}


-- | Get transaction summary from transaction id. Looks at both the database
-- and the memory (mempool) for the transaction. What we have at the mempool
-- are transactions that have to be written in the blockchain.
Expand Down
15 changes: 14 additions & 1 deletion explorer/src/Pos/Explorer/Web/TestServer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import Pos.Explorer.Web.ClientTypes (Byte, CAda (..), CAddress (..),
CAddressesFilter (..), CBlockEntry (..),
CBlockSummary (..), CGenesisAddressInfo (..),
CGenesisSummary (..), CHash (..), CTxBrief (..),
CTxEntry (..), CTxId (..), CTxSummary (..), mkCCoin)
CTxEntry (..), CTxId (..), CTxSummary (..), CUtxo (..),
mkCCoin)
import Pos.Explorer.Web.Error (ExplorerError (..))
import Pos.Web ()


----------------------------------------------------------------
-- Top level functionality
----------------------------------------------------------------
Expand All @@ -54,6 +56,7 @@ explorerHandlers =
, _txsLast = testTxsLast
, _txsSummary = testTxsSummary
, _addressSummary = testAddressSummary
, _addressUtxoBulk = testAddressUtxoBulk
, _epochPages = testEpochPageSearch
, _epochSlots = testEpochSlotSearch
, _genesisSummary = testGenesisSummary
Expand Down Expand Up @@ -185,6 +188,16 @@ testAddressSummary
-> Handler CAddressSummary
testAddressSummary _ = pure sampleAddressSummary

testAddressUtxoBulk
:: [CAddress]
-> Handler [CUtxo]
testAddressUtxoBulk _ = pure [CUtxo
{ cuId = CTxId $ CHash "8aac4a6b18fafa2783071c66519332157ce96c67e88fc0cc3cb04ba0342d12a1"
, cuOutIndex = 0
, cuAddress = CAddress "19F6U1Go5B4KakVoCZfzCtqNAWhUBprxVzL3JsGu74TEwQnXPvAKPUbvG8o4Qe5RaY8Z7WKLfxmNFwBqPV1NQ2hRpKkdEN"
, cuCoins = mkCCoin $ mkCoin 3
}]

testEpochSlotSearch
:: EpochIndex
-> Word16
Expand Down
9 changes: 7 additions & 2 deletions explorer/src/documentation/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ import Control.Lens (mapped, (?~))
import Data.Aeson (encode)
import qualified Data.ByteString.Lazy.Char8 as BSL8
import Data.Fixed (Fixed (..), Micro)
import Data.Swagger (Swagger, ToParamSchema (..), ToSchema (..),
declareNamedSchema, defaultSchemaOptions, description,
import Data.Swagger (NamedSchema (..), Swagger, ToParamSchema (..),
ToSchema (..), binarySchema, declareNamedSchema,
defaultSchemaOptions, description,
genericDeclareNamedSchema, host, info, name, title,
version)
import Data.Typeable (Typeable, typeRep)
Expand Down Expand Up @@ -85,6 +86,7 @@ instance ToParamSchema C.EpochIndex
instance ToSchema C.CTxSummary
instance ToSchema C.CTxEntry
instance ToSchema C.CTxBrief
instance ToSchema C.CUtxo
instance ToSchema C.CBlockSummary
instance ToSchema C.CBlockEntry
instance ToSchema C.CAddressType
Expand All @@ -100,6 +102,9 @@ instance ToParamSchema C.CAddressesFilter

deriving instance Generic Micro

instance ToSchema C.CByteString where
declareNamedSchema _ = return $ NamedSchema (Just "CByteString") binarySchema

-- | Instance for Either-based types (types we return as 'Right') in responses.
-- Due 'typeOf' these types must be 'Typeable'.
-- We need this instance for correct Swagger-specification.
Expand Down
2 changes: 2 additions & 0 deletions lib/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ dev: &dev
pendingTxResubmissionPeriod: 7 # seconds
walletProductionApi: false
walletTxCreationDisabled: false
explorerExtendedApi: false

tls: &dev_tls
ca:
Expand Down Expand Up @@ -310,6 +311,7 @@ mainnet_base: &mainnet_base
pendingTxResubmissionPeriod: 7 # seconds
walletProductionApi: true
walletTxCreationDisabled: false
explorerExtendedApi: false

tls: &mainnet_base_tls
ca:
Expand Down
15 changes: 15 additions & 0 deletions lib/src/Pos/Configuration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ module Pos.Configuration
, pendingTxResubmitionPeriod
, walletProductionApi
, walletTxCreationDisabled

-- * Explorer constants
, explorerExtendedApi
) where

import Universum
Expand Down Expand Up @@ -52,6 +55,9 @@ data NodeConfiguration = NodeConfiguration
, ccWalletTxCreationDisabled :: !Bool
-- ^ Disallow transaction creation or re-submission of
-- pending transactions by the wallet
, ccExplorerExtendedApi :: !Bool
-- ^ Enable explorer extended API for fetching more
-- info about addresses (like utxos) and bulk endpoints
} deriving (Show, Generic)

instance ToJSON NodeConfiguration where
Expand Down Expand Up @@ -91,3 +97,12 @@ walletProductionApi = ccWalletProductionApi $ nodeConfiguration
-- existing pending transactions.
walletTxCreationDisabled :: HasNodeConfiguration => Bool
walletTxCreationDisabled = ccWalletTxCreationDisabled $ nodeConfiguration

----------------------------------------------------------------------------
-- Explorer parameters
----------------------------------------------------------------------------

-- | If 'True', explorer extended API, like fetching utxos for address is enabled.
-- WARNING Those endpoints are potentially expensive!
explorerExtendedApi :: HasNodeConfiguration => Bool
explorerExtendedApi = ccExplorerExtendedApi $ nodeConfiguration