Skip to content

Commit

Permalink
Merge #1678
Browse files Browse the repository at this point in the history
1678: Migration endpoints for shelley and cardano-node's byron support r=paweljakubas a=paweljakubas

# Issue Number

<!-- Put here a reference to the issue this PR relates to and which requirements it tackles -->
#1675 

# Overview

<!-- Detail in a few bullet points the work accomplished in this PR -->

- [x] I have make ApiWalletMigrationPostData more flexible
- [x] I have added ShelleyMigration to API enpoints
- [x] I have added unit tests for the changed ApiWalletMigrationPostData
- [x] I have added integration tests to cardano-node's byron suite


# Comments


<!-- 
Don't forget to:

 ✓ Self-review your changes to make sure nothing unexpected slipped through
 ✓ Assign yourself to the PR
 ✓ Assign one or several reviewer(s)
 ✓ Once created, link this PR to its corresponding ticket
 ✓ Assign the PR to a corresponding milestone
 ✓ Acknowledge any changes required to the Wiki
-->


Co-authored-by: Pawel Jakubas <[email protected]>
Co-authored-by: Rodney Lorrimar <[email protected]>
  • Loading branch information
3 people authored May 26, 2020
2 parents 22e9097 + 34e7e11 commit 0318359
Show file tree
Hide file tree
Showing 16 changed files with 1,516 additions and 222 deletions.
2 changes: 1 addition & 1 deletion lib/byron/bench/Restore.hs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ bench_restoration
, WalletKey k
, NFData s
, Show s
, MaxSizeOf Address n k
, MaxSizeOf Address n ByronKey
, PersistState s
, PersistPrivateKey (k 'RootK)
, NetworkDiscriminantVal n
Expand Down
19 changes: 15 additions & 4 deletions lib/byron/src/Cardano/Wallet/Byron/Api/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import Cardano.Wallet.Api
, CoinSelections
, Network
, Proxy_
, ShelleyMigrations
, StakePools
, Transactions
, Wallets
Expand All @@ -54,6 +55,7 @@ import Cardano.Wallet.Api.Server
, listAddresses
, listTransactions
, listWallets
, migrateWallet
, mkLegacyWallet
, postExternalTransaction
, postIcarusWallet
Expand Down Expand Up @@ -118,6 +120,7 @@ server byron icarus ntp =
:<|> addresses
:<|> coinSelections
:<|> transactions
:<|> shelleyMigrations
:<|> stakePools
:<|> byronWallets
:<|> byronAddresses
Expand Down Expand Up @@ -149,6 +152,11 @@ server byron icarus ntp =
:<|> (\_ _ -> throwError err501)
:<|> (\_ _ -> throwError err501)

shelleyMigrations :: Server (ShelleyMigrations n)
shelleyMigrations =
(\_ -> throwError err501)
:<|> (\_ _ -> throwError err501)

stakePools :: Server (StakePools n)
stakePools =
throwError err501
Expand Down Expand Up @@ -225,7 +233,7 @@ server byron icarus ntp =
)
:<|>
(\wid r0 r1 s -> withLegacyLayer wid
(byron , listTransactions byron wid r0 r1 s)
(byron , listTransactions byron wid r0 r1 s)
(icarus, listTransactions icarus wid r0 r1 s)
)
:<|>
Expand All @@ -234,17 +242,20 @@ server byron icarus ntp =
(icarus, postTransactionFee icarus wid tx)
)
:<|> (\wid txid -> withLegacyLayer wid
(byron , deleteTransaction byron wid txid)
(byron , deleteTransaction byron wid txid)
(icarus, deleteTransaction icarus wid txid)
)

byronMigrations :: Server (ByronMigrations n)
byronMigrations =
(\wid -> withLegacyLayer wid
(byron , getMigrationInfo byron wid)
(byron , getMigrationInfo byron wid)
(icarus, getMigrationInfo icarus wid)
)
:<|> \_ _ -> throwError err501
:<|> (\wid m -> withLegacyLayer wid
(byron , migrateWallet byron wid m)
(icarus, migrateWallet icarus wid m)
)

network :: Server Network
network =
Expand Down
11 changes: 7 additions & 4 deletions lib/byron/src/Cardano/Wallet/Byron/Transaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import Cardano.Wallet.Byron.Transaction.Size
( MaxSizeOf, maxSizeOf, sizeOfSignedTx )
import Cardano.Wallet.Primitive.AddressDerivation
( Depth (..), NetworkDiscriminant (..), Passphrase (..), WalletKey (..) )
import Cardano.Wallet.Primitive.AddressDerivation.Byron
( ByronKey )
import Cardano.Wallet.Primitive.CoinSelection
( CoinSelection (..) )
import Cardano.Wallet.Primitive.Types
Expand Down Expand Up @@ -92,7 +94,7 @@ newTransactionLayer
:: forall (n :: NetworkDiscriminant) k t.
( t ~ IO Byron
, WalletKey k
, MaxSizeOf Address n k
, MaxSizeOf Address n ByronKey
)
=> Proxy n
-> ProtocolMagic
Expand Down Expand Up @@ -136,7 +138,7 @@ newTransactionLayer _proxy protocolMagic = TransactionLayer
Quantity $ sizeOfSignedTx (fst <$> inps) (outs <> map dummyOutput chngs)
where
dummyOutput :: Coin -> TxOut
dummyOutput = TxOut (dummyAddress @n @k)
dummyOutput = TxOut (dummyAddress @n)

_estimateMaxNumberOfInputs
:: Quantity "byte" Word16
Expand Down Expand Up @@ -237,9 +239,10 @@ genesisBlockFromTxOuts bp outs = Block
Tx (Hash $ blake2b256 bytes) [] [out]

dummyAddress
:: forall (n :: NetworkDiscriminant) k. (MaxSizeOf Address n k) => Address
:: forall (n :: NetworkDiscriminant). (MaxSizeOf Address n ByronKey)
=> Address
dummyAddress =
Address $ BS.replicate (maxSizeOf @Address @n @k) 0
Address $ BS.replicate (maxSizeOf @Address @n @ByronKey) 0

mkWitness
:: WalletKey k
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import Cardano.Wallet.Api.Types
, ApiT (..)
, ApiTransaction
, ApiUtxoStatistics
, ApiWalletMigrationInfo
, DecodeAddress (..)
, EncodeAddress (..)
, WalletStyle (..)
Expand All @@ -38,15 +39,15 @@ import Cardano.Wallet.Primitive.Types
import Control.Monad
( forM, forM_ )
import Data.Generics.Internal.VL.Lens
( (^.) )
( view, (^.) )
import Data.Quantity
( Quantity (..) )
import Data.Text
( Text )
import Numeric.Natural
( Natural )
import Test.Hspec
( SpecWith, describe, it, shouldBe, shouldNotBe )
( SpecWith, describe, it, shouldBe, shouldNotBe, shouldSatisfy )
import Test.Integration.Faucet
( nextWallet )
import Test.Integration.Framework.DSL
Expand All @@ -58,6 +59,7 @@ import Test.Integration.Framework.DSL
, emptyByronWalletFromXPrvWith
, emptyIcarusWallet
, emptyRandomWallet
, emptyRandomWalletMws
, eventually
, expectErrorMessage
, expectField
Expand All @@ -76,18 +78,21 @@ import Test.Integration.Framework.DSL
, fixtureRandomWalletAddrs
, fixtureRandomWalletMws
, fixtureRandomWalletWith
, getFromResponse
, icarusAddresses
, json
, randomAddresses
, request
, rootPrvKeyFromMnemonics
, verify
, walletId
, (.>)
)
import Test.Integration.Framework.Request
( RequestException )
import Test.Integration.Framework.TestData
( errMsg403Fee
( errMsg400ParseError
, errMsg403Fee
, errMsg403InputsDepleted
, errMsg403NotEnoughMoney_
, errMsg403UTxO
Expand Down Expand Up @@ -166,6 +171,15 @@ spec = do
scenario_TRANS_UTXO_01 @n fixtureIcarusWallet (fixtureIcarusWalletAddrs @n)
scenario_TRANS_UTXO_01 @n fixtureRandomWallet (fixtureRandomWalletAddrs @n)

describe "BYRON_MIGRATE" $ do
scenario_MIGRATE_01 @n fixtureRandomWallet
scenario_MIGRATE_02 @n fixtureRandomWallet 1
scenario_MIGRATE_02 @n fixtureRandomWallet 3
scenario_MIGRATE_02 @n fixtureRandomWallet 10
scenario_MIGRATE_02 @n fixtureIcarusWallet 1
scenario_MIGRATE_02 @n fixtureIcarusWallet 3
scenario_MIGRATE_02 @n fixtureIcarusWallet 10

--
-- Scenarios
--
Expand Down Expand Up @@ -690,6 +704,86 @@ scenario_TRANS_UTXO_01 fixtureSource fixtureTarget = it title $ \ctx -> do
where
title = "TRANS_UTXO_01 - one recipient multiple txs received"

scenario_MIGRATE_01
:: forall (n :: NetworkDiscriminant) t.
( DecodeAddress n
, EncodeAddress n
, PaymentAddress n ByronKey
)
=> (Context t -> IO ApiByronWallet)
-> SpecWith (Context t)
scenario_MIGRATE_01 fixtureSource = it title $ \ctx -> do
wSrc <- fixtureSource ctx

r <- request @[ApiTransaction n] ctx
(Link.migrateWallet wSrc)
Default
(NonJson "{passphrase:,}")
expectResponseCode @IO HTTP.status400 r
expectErrorMessage errMsg400ParseError r
where
title = "BYRON_MIGRATE_01 - invalid payload, parser error"

scenario_MIGRATE_02
:: forall (n :: NetworkDiscriminant) t.
( DecodeAddress n
, EncodeAddress n
, PaymentAddress n ByronKey
)
=> (Context t -> IO ApiByronWallet)
-> Int
-> SpecWith (Context t)
scenario_MIGRATE_02 fixtureSource addrCount = it title $ \ctx -> do
-- Restore a Byron wallet with funds, to act as a source wallet:
wSrc <- fixtureSource ctx
let originalBalance =
view (#balance . #available . #getQuantity) wSrc

-- Create an empty target wallet:
(wDest, mw) <- emptyRandomWalletMws ctx
let addresses :: [Text] =
take addrCount $ encodeAddress @n <$> randomAddresses @n mw

-- Calculate the expected migration fee:
r0 <- request @ApiWalletMigrationInfo ctx
(Link.getMigrationInfo wSrc) Default Empty
verify r0
[ expectResponseCode @IO HTTP.status200
, expectField #migrationCost (.> Quantity 0)
]
let expectedFee = getFromResponse (#migrationCost . #getQuantity) r0

-- Perform a migration from the source wallet to the target wallet:
r1 <- request @[ApiTransaction n] ctx
(Link.migrateWallet wSrc)
Default
(Json [json|
{ passphrase: #{fixturePassphrase}
, addresses: #{addresses}
}|])
verify r1
[ expectResponseCode @IO HTTP.status202
, expectField id (`shouldSatisfy` (not . null))
]

-- Check that funds become available in the target wallet:
let expectedBalance = originalBalance - expectedFee
eventually "Wallet has expectedBalance" $ do
r2 <- request @ApiByronWallet ctx
(Link.getWallet @'Byron wDest) Default Empty
verify r2
[ expectField
(#balance . #available)
(`shouldBe` Quantity expectedBalance)
, expectField
(#balance . #total)
(`shouldBe` Quantity expectedBalance)
]
where
title = "BYRON_MIGRATE_02 - after a migration operation successfully \
\completes, the correct amount eventually becomes available \
\in the target wallet for an arbitrary number of specified addresses."

--
-- More Elaborated Fixtures
--
Expand Down
15 changes: 9 additions & 6 deletions lib/byron/test/unit/Cardano/Wallet/Byron/TransactionSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ prop_rebalanceChangeOutputs sel onDangling = do
propSizeEstimation
:: forall n k.
( WalletKey k
, MaxSizeOf Address n k
, MaxSizeOf Address n ByronKey
)
=> ProtocolMagic
-> Gen CoinSelection
Expand All @@ -334,13 +334,16 @@ propSizeEstimation pm genSel genChngAddrs =
cbor = fromCoinSelection sel chngAddrs
size = fromIntegral $ BS.length $ CBOR.toStrictByteString cbor

-- We always go for the higher bound for change address payload's size,
-- so, we may end up with up to 12 extra bytes per change address in our
-- estimation.
-- As we have
-- maxSizeOf Icarus w/ Mainnet = 43
-- maxSizeOf Random w/ Mainnet = 76
-- The difference is 33, and we always go for the higher bound for
-- change address payload's size, so, we may end up with up to
-- 33 + 12 = 45 extra bytes per change address in our estimation.
-- For Icarus addresses, we can be as good as 4 bytes per change address
-- because there's no variance due to the derivation path encoded as
-- attributes (this only happens on random addresses).
margin = 12 * fromIntegral (length $ change sel)
margin = 45 * fromIntegral (length $ change sel)
realSizeSup = Quantity (size + margin)
realSizeInf = Quantity size
in
Expand Down Expand Up @@ -510,7 +513,7 @@ xprv seed =
goldenTestSignedTx
:: forall (n :: NetworkDiscriminant) k.
( k ~ IcarusKey
, MaxSizeOf Address n k
, MaxSizeOf Address n ByronKey
, PaymentAddress n k
)
=> Proxy n
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ import Cardano.Wallet.Api.Types
, ApiWalletDiscovery (..)
, ApiWalletMigrationInfo (..)
, DecodeAddress
, EncodeAddress (..)
, WalletStyle (..)
)
import Cardano.Wallet.Primitive.AddressDerivation
( PassphraseMaxLength (..), PassphraseMinLength (..) )
( PassphraseMaxLength (..), PassphraseMinLength (..), PaymentAddress )
import Cardano.Wallet.Primitive.AddressDerivation.Byron
( ByronKey )
import Cardano.Wallet.Primitive.Types
( SyncProgress (..) )
import Control.Monad
Expand Down Expand Up @@ -104,6 +107,8 @@ import qualified Network.HTTP.Types.Status as HTTP

spec :: forall n t.
( DecodeAddress n
, EncodeAddress n
, PaymentAddress n ByronKey
) => SpecWith (Context t)
spec = do
it "BYRON_CALCULATE_01 - \
Expand Down Expand Up @@ -547,8 +552,9 @@ spec = do
verify r
[ expectResponseCode @IO HTTP.status204
]
where
genMnemonics

where
genMnemonics
:: forall mw ent csz.
( ConsistentEntropy ent mw csz
, ValidEntropySize ent
Expand All @@ -557,4 +563,4 @@ spec = do
, mw ~ MnemonicWords ent
)
=> IO [Text]
genMnemonics = mnemonicToText . entropyToMnemonic @mw <$> genEntropy
genMnemonics = mnemonicToText . entropyToMnemonic @mw <$> genEntropy
Loading

0 comments on commit 0318359

Please sign in to comment.