module Cardano.CLI.Shelley.Run.Governance
  ( ShelleyGovernanceCmdError
  , renderShelleyGovernanceError
  , runGovernanceCmd
  ) where

import           Control.Monad (unless, when)
import           Control.Monad.Trans.Except (ExceptT)
import           Control.Monad.Trans.Except.Extra (firstExceptT, handleIOExceptT, left, newExceptT,
                   onLeft)
import           Data.Aeson (eitherDecode)
import qualified Data.ByteString.Lazy as LB
import           Data.Function ((&))
import qualified Data.List as List
import           Data.Text (Text)
import qualified Data.Text as Text

import           Cardano.Api
import           Cardano.Api.Shelley

import           Cardano.CLI.Shelley.Key (VerificationKeyOrHashOrFile,
                   readVerificationKeyOrHashOrFile, readVerificationKeyOrHashOrTextEnvFile)
import           Cardano.CLI.Shelley.Parsers
import           Cardano.CLI.Types

import           Cardano.Ledger.Alonzo.Scripts (CostModels (..))
import qualified Cardano.Ledger.Shelley.TxBody as Shelley


data ShelleyGovernanceCmdError
  = ShelleyGovernanceCmdTextEnvReadError !(FileError TextEnvelopeError)
  | ShelleyGovernanceCmdKeyReadError !(FileError InputDecodeError)
  | ShelleyGovernanceCmdCostModelReadError !(FileError ())
  | ShelleyGovernanceCmdTextEnvWriteError !(FileError ())
  | ShelleyGovernanceCmdEmptyUpdateProposalError
  | ShelleyGovernanceCmdMIRCertificateKeyRewardMistmach
      !FilePath
      !Int
      -- ^ Number of stake verification keys
      !Int
      -- ^ Number of reward amounts
  | ShelleyGovernanceCmdCostModelsJsonDecodeErr !FilePath !Text
  | ShelleyGovernanceCmdEmptyCostModel !FilePath
  deriving Int -> ShelleyGovernanceCmdError -> ShowS
[ShelleyGovernanceCmdError] -> ShowS
ShelleyGovernanceCmdError -> FilePath
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [ShelleyGovernanceCmdError] -> ShowS
$cshowList :: [ShelleyGovernanceCmdError] -> ShowS
show :: ShelleyGovernanceCmdError -> FilePath
$cshow :: ShelleyGovernanceCmdError -> FilePath
showsPrec :: Int -> ShelleyGovernanceCmdError -> ShowS
$cshowsPrec :: Int -> ShelleyGovernanceCmdError -> ShowS
Show

renderShelleyGovernanceError :: ShelleyGovernanceCmdError -> Text
renderShelleyGovernanceError :: ShelleyGovernanceCmdError -> Text
renderShelleyGovernanceError ShelleyGovernanceCmdError
err =
  case ShelleyGovernanceCmdError
err of
    ShelleyGovernanceCmdTextEnvReadError FileError TextEnvelopeError
fileErr -> FilePath -> Text
Text.pack (forall e. Error e => e -> FilePath
displayError FileError TextEnvelopeError
fileErr)
    ShelleyGovernanceCmdKeyReadError FileError InputDecodeError
fileErr -> FilePath -> Text
Text.pack (forall e. Error e => e -> FilePath
displayError FileError InputDecodeError
fileErr)
    ShelleyGovernanceCmdTextEnvWriteError FileError ()
fileErr -> FilePath -> Text
Text.pack (forall e. Error e => e -> FilePath
displayError FileError ()
fileErr)
    -- TODO: The equality check is still not working for empty update proposals.
    ShelleyGovernanceCmdError
ShelleyGovernanceCmdEmptyUpdateProposalError ->
      Text
"Empty update proposals are not allowed"
    ShelleyGovernanceCmdMIRCertificateKeyRewardMistmach FilePath
fp Int
numVKeys Int
numRwdAmts ->
       Text
"Error creating the MIR certificate at: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
textShow FilePath
fp
       forall a. Semigroup a => a -> a -> a
<> Text
" The number of staking keys: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
textShow Int
numVKeys
       forall a. Semigroup a => a -> a -> a
<> Text
" and the number of reward amounts: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
textShow Int
numRwdAmts
       forall a. Semigroup a => a -> a -> a
<> Text
" are not equivalent."
    ShelleyGovernanceCmdCostModelsJsonDecodeErr FilePath
fp Text
err' ->
      Text
"Error decoding cost model: " forall a. Semigroup a => a -> a -> a
<> Text
err' forall a. Semigroup a => a -> a -> a
<> Text
" at: " forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
Text.pack FilePath
fp
    ShelleyGovernanceCmdEmptyCostModel FilePath
fp ->
      Text
"The decoded cost model was empty at: " forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
Text.pack FilePath
fp
    ShelleyGovernanceCmdCostModelReadError FileError ()
err' ->
      Text
"Error reading the cost model: " forall a. Semigroup a => a -> a -> a
<> FilePath -> Text
Text.pack (forall e. Error e => e -> FilePath
displayError FileError ()
err')


runGovernanceCmd :: GovernanceCmd -> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceCmd :: GovernanceCmd -> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceCmd (GovernanceMIRPayStakeAddressesCertificate MIRPot
mirpot [StakeAddress]
vKeys [Lovelace]
rewards OutputFile
out) =
  MIRPot
-> [StakeAddress]
-> [Lovelace]
-> OutputFile
-> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceMIRCertificatePayStakeAddrs MIRPot
mirpot [StakeAddress]
vKeys [Lovelace]
rewards OutputFile
out
runGovernanceCmd (GovernanceMIRTransfer Lovelace
amt OutputFile
out TransferDirection
direction) =
  Lovelace
-> OutputFile
-> TransferDirection
-> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceMIRCertificateTransfer Lovelace
amt OutputFile
out TransferDirection
direction
runGovernanceCmd (GovernanceGenesisKeyDelegationCertificate VerificationKeyOrHashOrFile GenesisKey
genVk VerificationKeyOrHashOrFile GenesisDelegateKey
genDelegVk VerificationKeyOrHashOrFile VrfKey
vrfVk OutputFile
out) =
  VerificationKeyOrHashOrFile GenesisKey
-> VerificationKeyOrHashOrFile GenesisDelegateKey
-> VerificationKeyOrHashOrFile VrfKey
-> OutputFile
-> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceGenesisKeyDelegationCertificate VerificationKeyOrHashOrFile GenesisKey
genVk VerificationKeyOrHashOrFile GenesisDelegateKey
genDelegVk VerificationKeyOrHashOrFile VrfKey
vrfVk OutputFile
out
runGovernanceCmd (GovernanceUpdateProposal OutputFile
out EpochNo
eNo [VerificationKeyFile]
genVKeys ProtocolParametersUpdate
ppUp Maybe FilePath
mCostModelFp) =
  OutputFile
-> EpochNo
-> [VerificationKeyFile]
-> ProtocolParametersUpdate
-> Maybe FilePath
-> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceUpdateProposal OutputFile
out EpochNo
eNo [VerificationKeyFile]
genVKeys ProtocolParametersUpdate
ppUp Maybe FilePath
mCostModelFp

runGovernanceMIRCertificatePayStakeAddrs
  :: Shelley.MIRPot
  -> [StakeAddress] -- ^ Stake addresses
  -> [Lovelace]     -- ^ Corresponding reward amounts (same length)
  -> OutputFile
  -> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceMIRCertificatePayStakeAddrs :: MIRPot
-> [StakeAddress]
-> [Lovelace]
-> OutputFile
-> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceMIRCertificatePayStakeAddrs MIRPot
mirPot [StakeAddress]
sAddrs [Lovelace]
rwdAmts (OutputFile FilePath
oFp) = do

    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Int
length [StakeAddress]
sAddrs forall a. Eq a => a -> a -> Bool
== forall (t :: * -> *) a. Foldable t => t a -> Int
length [Lovelace]
rwdAmts) forall a b. (a -> b) -> a -> b
$
      forall (m :: * -> *) x a. Monad m => x -> ExceptT x m a
left forall a b. (a -> b) -> a -> b
$ FilePath -> Int -> Int -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdMIRCertificateKeyRewardMistmach
               FilePath
oFp (forall (t :: * -> *) a. Foldable t => t a -> Int
length [StakeAddress]
sAddrs) (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Lovelace]
rwdAmts)

    let sCreds :: [StakeCredential]
sCreds  = forall a b. (a -> b) -> [a] -> [b]
map StakeAddress -> StakeCredential
stakeAddressCredential [StakeAddress]
sAddrs
        mirCert :: Certificate
mirCert = MIRPot -> MIRTarget -> Certificate
makeMIRCertificate MIRPot
mirPot ([(StakeCredential, Lovelace)] -> MIRTarget
StakeAddressesMIR forall a b. (a -> b) -> a -> b
$ forall a b. [a] -> [b] -> [(a, b)]
zip [StakeCredential]
sCreds [Lovelace]
rwdAmts)

    forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT FileError () -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdTextEnvWriteError
      forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) x a. m (Either x a) -> ExceptT x m a
newExceptT
      forall a b. (a -> b) -> a -> b
$ forall a.
HasTextEnvelope a =>
FilePath
-> Maybe TextEnvelopeDescr -> a -> IO (Either (FileError ()) ())
writeFileTextEnvelope FilePath
oFp (forall a. a -> Maybe a
Just TextEnvelopeDescr
mirCertDesc) Certificate
mirCert
  where
    mirCertDesc :: TextEnvelopeDescr
    mirCertDesc :: TextEnvelopeDescr
mirCertDesc = TextEnvelopeDescr
"Move Instantaneous Rewards Certificate"

runGovernanceMIRCertificateTransfer
  :: Lovelace
  -> OutputFile
  -> TransferDirection
  -> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceMIRCertificateTransfer :: Lovelace
-> OutputFile
-> TransferDirection
-> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceMIRCertificateTransfer Lovelace
ll (OutputFile FilePath
oFp) TransferDirection
direction = do
  Certificate
mirCert <- case TransferDirection
direction of
                 TransferDirection
TransferToReserves ->
                   forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. MIRPot -> MIRTarget -> Certificate
makeMIRCertificate MIRPot
Shelley.TreasuryMIR forall a b. (a -> b) -> a -> b
$ Lovelace -> MIRTarget
SendToReservesMIR Lovelace
ll
                 TransferDirection
TransferToTreasury ->
                   forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. MIRPot -> MIRTarget -> Certificate
makeMIRCertificate MIRPot
Shelley.ReservesMIR forall a b. (a -> b) -> a -> b
$ Lovelace -> MIRTarget
SendToTreasuryMIR Lovelace
ll

  forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT FileError () -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdTextEnvWriteError
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) x a. m (Either x a) -> ExceptT x m a
newExceptT
    forall a b. (a -> b) -> a -> b
$ forall a.
HasTextEnvelope a =>
FilePath
-> Maybe TextEnvelopeDescr -> a -> IO (Either (FileError ()) ())
writeFileTextEnvelope FilePath
oFp (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ TransferDirection -> TextEnvelopeDescr
mirCertDesc TransferDirection
direction) Certificate
mirCert
 where
  mirCertDesc :: TransferDirection -> TextEnvelopeDescr
  mirCertDesc :: TransferDirection -> TextEnvelopeDescr
mirCertDesc TransferDirection
TransferToTreasury = TextEnvelopeDescr
"MIR Certificate Send To Treasury"
  mirCertDesc TransferDirection
TransferToReserves = TextEnvelopeDescr
"MIR Certificate Send To Reserves"


runGovernanceGenesisKeyDelegationCertificate
  :: VerificationKeyOrHashOrFile GenesisKey
  -> VerificationKeyOrHashOrFile GenesisDelegateKey
  -> VerificationKeyOrHashOrFile VrfKey
  -> OutputFile
  -> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceGenesisKeyDelegationCertificate :: VerificationKeyOrHashOrFile GenesisKey
-> VerificationKeyOrHashOrFile GenesisDelegateKey
-> VerificationKeyOrHashOrFile VrfKey
-> OutputFile
-> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceGenesisKeyDelegationCertificate VerificationKeyOrHashOrFile GenesisKey
genVkOrHashOrFp
                                             VerificationKeyOrHashOrFile GenesisDelegateKey
genDelVkOrHashOrFp
                                             VerificationKeyOrHashOrFile VrfKey
vrfVkOrHashOrFp
                                             (OutputFile FilePath
oFp) = do
    Hash GenesisKey
genesisVkHash <- forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT FileError InputDecodeError -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdKeyReadError
      forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) x a. m (Either x a) -> ExceptT x m a
newExceptT
      forall a b. (a -> b) -> a -> b
$ forall keyrole.
Key keyrole =>
AsType keyrole
-> VerificationKeyOrHashOrFile keyrole
-> IO (Either (FileError InputDecodeError) (Hash keyrole))
readVerificationKeyOrHashOrTextEnvFile AsType GenesisKey
AsGenesisKey VerificationKeyOrHashOrFile GenesisKey
genVkOrHashOrFp
    Hash GenesisDelegateKey
genesisDelVkHash <-forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT FileError InputDecodeError -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdKeyReadError
      forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) x a. m (Either x a) -> ExceptT x m a
newExceptT
      forall a b. (a -> b) -> a -> b
$ forall keyrole.
Key keyrole =>
AsType keyrole
-> VerificationKeyOrHashOrFile keyrole
-> IO (Either (FileError InputDecodeError) (Hash keyrole))
readVerificationKeyOrHashOrTextEnvFile AsType GenesisDelegateKey
AsGenesisDelegateKey VerificationKeyOrHashOrFile GenesisDelegateKey
genDelVkOrHashOrFp
    Hash VrfKey
vrfVkHash <- forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT FileError InputDecodeError -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdKeyReadError
      forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) x a. m (Either x a) -> ExceptT x m a
newExceptT
      forall a b. (a -> b) -> a -> b
$ forall keyrole.
(Key keyrole, SerialiseAsBech32 (VerificationKey keyrole)) =>
AsType keyrole
-> VerificationKeyOrHashOrFile keyrole
-> IO (Either (FileError InputDecodeError) (Hash keyrole))
readVerificationKeyOrHashOrFile AsType VrfKey
AsVrfKey VerificationKeyOrHashOrFile VrfKey
vrfVkOrHashOrFp
    forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT FileError () -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdTextEnvWriteError
      forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) x a. m (Either x a) -> ExceptT x m a
newExceptT
      forall a b. (a -> b) -> a -> b
$ forall a.
HasTextEnvelope a =>
FilePath
-> Maybe TextEnvelopeDescr -> a -> IO (Either (FileError ()) ())
writeFileTextEnvelope FilePath
oFp (forall a. a -> Maybe a
Just TextEnvelopeDescr
genKeyDelegCertDesc)
      forall a b. (a -> b) -> a -> b
$ Hash GenesisKey
-> Hash GenesisDelegateKey -> Hash VrfKey -> Certificate
makeGenesisKeyDelegationCertificate Hash GenesisKey
genesisVkHash Hash GenesisDelegateKey
genesisDelVkHash Hash VrfKey
vrfVkHash
  where
    genKeyDelegCertDesc :: TextEnvelopeDescr
    genKeyDelegCertDesc :: TextEnvelopeDescr
genKeyDelegCertDesc = TextEnvelopeDescr
"Genesis Key Delegation Certificate"

runGovernanceUpdateProposal
  :: OutputFile
  -> EpochNo
  -> [VerificationKeyFile]
  -- ^ Genesis verification keys
  -> ProtocolParametersUpdate
  -> Maybe FilePath -- ^ Cost models file path
  -> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceUpdateProposal :: OutputFile
-> EpochNo
-> [VerificationKeyFile]
-> ProtocolParametersUpdate
-> Maybe FilePath
-> ExceptT ShelleyGovernanceCmdError IO ()
runGovernanceUpdateProposal (OutputFile FilePath
upFile) EpochNo
eNo [VerificationKeyFile]
genVerKeyFiles ProtocolParametersUpdate
upPprams Maybe FilePath
mCostModelFp = do
  ProtocolParametersUpdate
finalUpPprams <- case Maybe FilePath
mCostModelFp of
    Maybe FilePath
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ProtocolParametersUpdate
upPprams
    Just FilePath
fp -> do
      ByteString
costModelsBs <- forall (m :: * -> *) x a.
MonadIO m =>
(IOException -> x) -> IO a -> ExceptT x m a
handleIOExceptT (FileError () -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdCostModelReadError forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e. FilePath -> IOException -> FileError e
FileIOError FilePath
fp) forall a b. (a -> b) -> a -> b
$ FilePath -> IO ByteString
LB.readFile FilePath
fp

      CostModels
cModels <- forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a. FromJSON a => ByteString -> Either FilePath a
eitherDecode ByteString
costModelsBs)
        forall a b. a -> (a -> b) -> b
& forall e x (m :: * -> *) a.
Monad m =>
(e -> ExceptT x m a) -> ExceptT x m (Either e a) -> ExceptT x m a
onLeft (forall (m :: * -> *) x a. Monad m => x -> ExceptT x m a
left forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdCostModelsJsonDecodeErr FilePath
fp forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
Text.pack)

      forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall (t :: * -> *) a. Foldable t => t a -> Bool
List.null (CostModels -> Map Language CostModel
unCostModels CostModels
cModels)) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) x a. Monad m => x -> ExceptT x m a
left (FilePath -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdEmptyCostModel FilePath
fp)

      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ ProtocolParametersUpdate
upPprams {protocolUpdateCostModels :: Map AnyPlutusScriptVersion CostModel
protocolUpdateCostModels = CostModels -> Map AnyPlutusScriptVersion CostModel
fromAlonzoCostModels CostModels
cModels}

  forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ProtocolParametersUpdate
finalUpPprams forall a. Eq a => a -> a -> Bool
== forall a. Monoid a => a
mempty) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) x a. Monad m => x -> ExceptT x m a
left ShelleyGovernanceCmdError
ShelleyGovernanceCmdEmptyUpdateProposalError

  [VerificationKey GenesisKey]
genVKeys <- forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence
    [ forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT FileError TextEnvelopeError -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdTextEnvReadError forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) x a. m (Either x a) -> ExceptT x m a
newExceptT forall a b. (a -> b) -> a -> b
$ forall a.
HasTextEnvelope a =>
AsType a -> FilePath -> IO (Either (FileError TextEnvelopeError) a)
readFileTextEnvelope (forall a. AsType a -> AsType (VerificationKey a)
AsVerificationKey AsType GenesisKey
AsGenesisKey) FilePath
vkeyFile
    | VerificationKeyFile FilePath
vkeyFile <- [VerificationKeyFile]
genVerKeyFiles
    ]
  let genKeyHashes :: [Hash GenesisKey]
genKeyHashes = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall keyrole.
Key keyrole =>
VerificationKey keyrole -> Hash keyrole
verificationKeyHash [VerificationKey GenesisKey]
genVKeys
      upProp :: UpdateProposal
upProp = ProtocolParametersUpdate
-> [Hash GenesisKey] -> EpochNo -> UpdateProposal
makeShelleyUpdateProposal ProtocolParametersUpdate
finalUpPprams [Hash GenesisKey]
genKeyHashes EpochNo
eNo

  forall (m :: * -> *) x y a.
Functor m =>
(x -> y) -> ExceptT x m a -> ExceptT y m a
firstExceptT FileError () -> ShelleyGovernanceCmdError
ShelleyGovernanceCmdTextEnvWriteError forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) x a. m (Either x a) -> ExceptT x m a
newExceptT forall a b. (a -> b) -> a -> b
$ forall a.
HasTextEnvelope a =>
FilePath
-> Maybe TextEnvelopeDescr -> a -> IO (Either (FileError ()) ())
writeFileTextEnvelope FilePath
upFile forall a. Maybe a
Nothing UpdateProposal
upProp