Skip to content

Commit

Permalink
revitalize old Voting
Browse files Browse the repository at this point in the history
  • Loading branch information
paweljakubas committed Mar 1, 2024
1 parent 0dfcb11 commit 2ef2840
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/integration/cardano-wallet-integration.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ library scenarios
Test.Integration.Scenario.API.Shelley.Transactions
Test.Integration.Scenario.API.Shelley.TransactionsNew
Test.Integration.Scenario.API.Shelley.Wallets
Test.Integration.Scenario.API.Voting
Test.Integration.Scenario.CLI.Byron.Addresses
Test.Integration.Scenario.CLI.Byron.Wallets
Test.Integration.Scenario.CLI.Miscellaneous
Expand Down
11 changes: 11 additions & 0 deletions lib/integration/framework/Test/Integration/Framework/DSL.hs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ module Test.Integration.Framework.DSL
-- * Delegation helpers
, notDelegating
, delegating
, onlyVoting
, votingAndDelegating
, getSlotParams
, arbitraryStake
Expand Down Expand Up @@ -3523,6 +3524,16 @@ delegating pidActive nexts = (notDelegating nexts)
{ active = ApiWalletDelegationNext Delegating (Just pidActive) Nothing Nothing
}

onlyVoting
:: ApiT DRep
-- ^ voting
-> [(Maybe (ApiT PoolId), EpochInfo)]
-- ^ Pools to be joined & epoch at which the new delegation will become active
-> ApiWalletDelegation
onlyVoting drep nexts = (notDelegating nexts)
{ active = ApiWalletDelegationNext Voting Nothing (Just drep) Nothing
}

votingAndDelegating
:: ApiT PoolId
-- ^ Pool joined
Expand Down
2 changes: 2 additions & 0 deletions lib/integration/scenarios/Test/Integration/Run.hs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import qualified Test.Integration.Scenario.API.Shelley.StakePools as StakePools
import qualified Test.Integration.Scenario.API.Shelley.Transactions as Transactions
import qualified Test.Integration.Scenario.API.Shelley.TransactionsNew as TransactionsNew
import qualified Test.Integration.Scenario.API.Shelley.Wallets as Wallets
import qualified Test.Integration.Scenario.API.Voting as Voting
import qualified Test.Integration.Scenario.CLI.Miscellaneous as MiscellaneousCLI
import qualified Test.Integration.Scenario.CLI.Network as NetworkCLI
import qualified Test.Integration.Scenario.CLI.Port as PortCLI
Expand Down Expand Up @@ -121,6 +122,7 @@ main = withTestsSetup $ \testDir (tr, tracers) -> do
StakePools.spec @n
ByronTransactions.spec @n
ByronHWWallets.spec @n
Voting.spec @n

-- Possible conflict with StakePools - mark as not parallizable
sequential Settings.spec
Expand Down
243 changes: 243 additions & 0 deletions lib/integration/scenarios/Test/Integration/Scenario/API/Voting.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Test.Integration.Scenario.API.Voting (spec) where

import Prelude

import Cardano.Wallet.Address.Derivation
( DerivationIndex (..)
)
import Cardano.Wallet.Api.Types
( ApiAnyCertificate (..)
, ApiCertificate (..)
, ApiConstructTransaction (..)
, ApiDecodedTransaction
, ApiSerialisedTransaction (..)
, ApiT (..)
, ApiTransaction
, ApiTxId (..)
, ApiWallet (..)
, WalletStyle (..)
)
import Cardano.Wallet.Api.Types.Amount
( ApiAmount (ApiAmount)
)
import Cardano.Wallet.Primitive.NetworkId
( HasSNetworkId
)
import Cardano.Wallet.Primitive.Types.DRep
( DRep (..)
)
import Cardano.Wallet.Primitive.Types.Tx.TxMeta
( Direction (..)
, TxStatus (..)
)
import Control.Monad.Trans.Resource
( runResourceT
)
import Data.Aeson
( toJSON
)
import Test.Hspec
( SpecWith
, describe
)
import Test.Hspec.Expectations.Lifted
( shouldBe
)
import Test.Hspec.Extra
( it
)
import Test.Integration.Framework.DSL
( Context (..)
, Headers (..)
, Payload (..)
, eventually
, expectField
, expectResponseCode
, expectSuccess
, fixtureWallet
, getFromResponse
, getResponse
, json
, noBabbage
, notDelegating
, onlyVoting
, request
, signTx
, submitTxWithWid
, verify
, waitNumberOfEpochBoundaries
)

import qualified Cardano.Wallet.Api.Link as Link
import qualified Data.List.NonEmpty as NE
import qualified Network.HTTP.Types.Status as HTTP

spec :: forall n. HasSNetworkId n => SpecWith Context
spec = describe "VOTING_TRANSACTIONS" $ do
it "VOTING_01a - Can vote and revote" $ \ctx -> runResourceT $ do
noBabbage ctx "voting supported in Conway onwards"
src <- fixtureWallet ctx

let getSrcWallet =
let endpoint = Link.getWallet @'Shelley src
in request @ApiWallet ctx endpoint Default Empty
getSrcWallet >>= flip verify
[ expectField #delegation (`shouldBe` notDelegating [])
]

let depositAmt = ApiAmount 1_000_000
let voteNoConfidence = Json [json|{
"vote": "no_confidence"
}|]
rTx1 <- request @(ApiConstructTransaction n) ctx
(Link.createUnsignedTransaction @'Shelley src) Default voteNoConfidence
verify rTx1
[ expectResponseCode HTTP.status202
, expectField (#coinSelection . #depositsTaken) (`shouldBe` [depositAmt])
, expectField (#coinSelection . #depositsReturned) (`shouldBe` [])
]

let ApiSerialisedTransaction apiTx1 _ = getFromResponse #transaction rTx1
signedTx1 <- signTx ctx src apiTx1 [ expectResponseCode HTTP.status202 ]

-- as we are joining for the first time we expect two certificates
let stakeKeyDerPath = NE.fromList
[ ApiT (DerivationIndex 2_147_485_500)
, ApiT (DerivationIndex 2_147_485_463)
, ApiT (DerivationIndex 2_147_483_648)
, ApiT (DerivationIndex 2)
, ApiT (DerivationIndex 0)
]
let registerStakeKeyCert =
WalletDelegationCertificate $ RegisterRewardAccount stakeKeyDerPath
let voting1 = ApiT NoConfidence
let votingCert1 =
WalletDelegationCertificate $ CastVote stakeKeyDerPath voting1

let decodePayload1 = Json (toJSON signedTx1)
rDecodedTx1 <- request @(ApiDecodedTransaction n) ctx
(Link.decodeTransaction @'Shelley src) Default decodePayload1
verify rDecodedTx1
[ expectResponseCode HTTP.status202
, expectField #certificates (`shouldBe` [registerStakeKeyCert, votingCert1])
, expectField #depositsTaken (`shouldBe` [depositAmt])
, expectField #depositsReturned (`shouldBe` [])
]

-- Submit tx
submittedTx1 <- submitTxWithWid ctx src signedTx1
verify submittedTx1
[ expectSuccess
, expectResponseCode HTTP.status202
]

eventually "Wallet has voted and deposit info persists" $ do
rJoin' <- request @(ApiTransaction n) ctx
(Link.getTransaction @'Shelley src
(getResponse submittedTx1))
Default Empty
verify rJoin'
[ expectResponseCode HTTP.status200
, expectField (#status . #getApiT) (`shouldBe` InLedger)
, expectField (#direction . #getApiT) (`shouldBe` Outgoing)
, expectField #depositTaken (`shouldBe` depositAmt)
, expectField #depositReturned (`shouldBe` ApiAmount 0)
]

let txId1 = getFromResponse #id submittedTx1
let link1 = Link.getTransaction @'Shelley src (ApiTxId txId1)
eventually "Voting transaction is in ledger" $ do
request @(ApiTransaction n) ctx link1 Default Empty
>>= flip verify
[ expectResponseCode HTTP.status200
, expectField (#direction . #getApiT) (`shouldBe` Outgoing)
, expectField (#status . #getApiT) (`shouldBe` InLedger)
, expectField #metadata (`shouldBe` Nothing)
]

waitNumberOfEpochBoundaries 2 ctx

eventually "Wallet is voting no confidence" $ do
getSrcWallet >>= flip verify
[ expectField #delegation (`shouldBe` onlyVoting voting1 [])
]

let voteAbstain = Json [json|{
"vote": "abstain"
}|]
rTx2 <- request @(ApiConstructTransaction n) ctx
(Link.createUnsignedTransaction @'Shelley src) Default voteAbstain
verify rTx2
[ expectResponseCode HTTP.status202
, expectField (#coinSelection . #depositsTaken) (`shouldBe` [])
, expectField (#coinSelection . #depositsReturned) (`shouldBe` [])
]

let ApiSerialisedTransaction apiTx2 _ = getFromResponse #transaction rTx2
signedTx2 <- signTx ctx src apiTx2 [ expectResponseCode HTTP.status202 ]

let voting2 = ApiT Abstain
let votingCert2 =
WalletDelegationCertificate $ CastVote stakeKeyDerPath voting2

let decodePayload2 = Json (toJSON signedTx2)
rDecodedTx2 <- request @(ApiDecodedTransaction n) ctx
(Link.decodeTransaction @'Shelley src) Default decodePayload2
verify rDecodedTx2
[ expectResponseCode HTTP.status202
, expectField #certificates (`shouldBe` [votingCert2])
, expectField #depositsTaken (`shouldBe` [])
, expectField #depositsReturned (`shouldBe` [])
]

-- Submit tx
submittedTx2 <- submitTxWithWid ctx src signedTx2
verify submittedTx2
[ expectSuccess
, expectResponseCode HTTP.status202
]

eventually "Wallet has voted again" $ do
rJoin' <- request @(ApiTransaction n) ctx
(Link.getTransaction @'Shelley src
(getResponse submittedTx2))
Default Empty
verify rJoin'
[ expectResponseCode HTTP.status200
, expectField (#status . #getApiT) (`shouldBe` InLedger)
, expectField (#direction . #getApiT) (`shouldBe` Outgoing)
, expectField #depositTaken (`shouldBe` ApiAmount 0)
, expectField #depositReturned (`shouldBe` ApiAmount 0)
]

let txId2 = getFromResponse #id submittedTx2
let link2 = Link.getTransaction @'Shelley src (ApiTxId txId2)
eventually "Re-voting transaction is in ledger" $ do
request @(ApiTransaction n) ctx link2 Default Empty
>>= flip verify
[ expectResponseCode HTTP.status200
, expectField (#direction . #getApiT) (`shouldBe` Outgoing)
, expectField (#status . #getApiT) (`shouldBe` InLedger)
, expectField #metadata (`shouldBe` Nothing)
]

waitNumberOfEpochBoundaries 2 ctx

eventually "Wallet is voting abstain" $ do
getSrcWallet >>= flip verify
[ expectField #delegation (`shouldBe` onlyVoting voting2 [])
]

0 comments on commit 2ef2840

Please sign in to comment.