Migrate Rpc.Transaction test to Cardano.Api.Experimental API
## Summary
The RPC transaction integration test (`cardano-testnet/test/.../Rpc/Transaction.hs`) currently uses the old `Cardano.Api` transaction-building API. It should be migrated to the new `Cardano.Api.Experimental` API to:
- Align with the direction of cardano-api (old API is being deprecated)
- Use ledger-aligned types directly, reducing impedance mismatch
- Serve as a reference example for RPC + experimental API integration
## Current old-API patterns to replace
The test currently uses these old-API constructs:
1. **Era handling**: `ConwayEraOnwards`/`ShelleyBasedEra` with `convert` — replace with `Exp.Era` (`Exp.ConwayEra`)
2. **TxOut construction**: `TxOut addr (lovelaceToTxOutValue sbe coin) TxOutDatumNone ReferenceScriptNone` — replace with `Exp.TxOut (Ledger.mkBasicTxOut ledgerAddr value)`
3. **TxBodyContent**: `defaultTxBodyContent sbe` with old setters and wrapper types (`BuildTxWith`, `TxFeeExplicit`, `KeyWitness KeyWitnessForSpending`, `LedgerProtocolParameters`) — replace with `Exp.defaultTxBodyContent` + experimental setters using direct ledger types
4. **Tx creation**: `createTransactionBody sbe content` — replace with `Exp.makeUnsignedTx era content`
5. **Tx signing**: `signShelleyTransaction sbe txBody [wit0]` — replace with `Exp.makeKeyWitness era unsignedTx wit0` then `Exp.signTx era [] [keyWit] unsignedTx`
6. **TxId extraction**: `getTxId $ getTxBody signedTx` — replace with `Exp.hashTxBody (ledgerTx ^. L.bodyTxL)` or equivalent
7. **Serialization**: `serialiseToCBOR signedTx` — replace with `serialiseToRawBytes (Exp.SignedTx ledgerTx)`
## Migration plan
### Step 1: Update imports
- Add `import qualified Cardano.Api.Experimental as Exp`
- Add `import qualified Cardano.Api.Experimental.Tx as Exp`
- Keep `Cardano.Api` for shared types still needed (address deserialization, `TxIn`, `TxIx`, `ShelleyWitnessSigningKey`, etc.)
- Keep `Cardano.Api.Ledger` for direct ledger types (`Addr`, `MaryValue`, `Coin`, etc.)
### Step 2: Update era handling
- Replace `(ceo, eraProxy) = (conwayBasedEra, asType)` with `era = Exp.ConwayEra`
- Derive `sbe = Exp.convert era` only where testnet infrastructure still requires `ShelleyBasedEra` (e.g., `cardanoNodeEra = AnyShelleyBasedEra sbe`)
- Address deserialization can stay as old-API (`deserialiseAddress`), converting to ledger `Addr` via `toShelleyAddr` where needed for tx outputs
### Step 3: Update transaction building
Replace old-style `TxBodyContent` construction:
```haskell
-- OLD
let content =
defaultTxBodyContent sbe
& setTxIns [(txIn0, pure $ KeyWitness KeyWitnessForSpending)]
& setTxFee (TxFeeExplicit sbe (L.Coin fee))
& setTxOuts [TxOut addr1 (lovelaceToTxOutValue sbe $ L.Coin amount) TxOutDatumNone ReferenceScriptNone, ...]
& setTxProtocolParams (pure . pure $ LedgerProtocolParameters pparams)
```
With experimental-style:
```haskell
-- NEW
let ledgerAddr0 = toShelleyAddr addr0
ledgerAddr1 = toShelleyAddr addr1
mkOut addr coin = Exp.obtainCommonConstraints era $
Exp.TxOut (Ledger.mkBasicTxOut addr (Ledger.valueFromList coin []))
content =
Exp.defaultTxBodyContent
& Exp.setTxIns [(txIn0, Exp.AnyKeyWitnessPlaceholder)]
& Exp.setTxFee (L.Coin fee)
& Exp.setTxOuts [mkOut ledgerAddr1 amount, mkOut ledgerAddr0 change]
& Exp.setTxProtocolParams (Just pparams)
```
### Step 4: Update transaction creation and signing
```haskell
-- OLD
txBody <- H.leftFail $ createTransactionBody sbe content
let signedTx = signShelleyTransaction sbe txBody [wit0]
-- NEW
let unsignedTx = Exp.makeUnsignedTx era content
keyWit = Exp.makeKeyWitness era unsignedTx wit0
Exp.SignedTx signedLedgerTx = Exp.signTx era [] [keyWit] unsignedTx
```
### Step 5: Update TxId extraction and serialization
```haskell
-- OLD
txId' <- H.noteShow . getTxId $ getTxBody signedTx
... serialiseToCBOR signedTx
-- NEW
txId' <- H.noteShow $ Exp.hashTxBody (signedLedgerTx ^. L.bodyTxL)
... serialiseToRawBytes (Exp.SignedTx signedLedgerTx)
```
### Step 6: Verify `utxoRpcPParamsToProtocolParams` compatibility
`utxoRpcPParamsToProtocolParams` already takes `Era era` and returns `L.PParams (ShelleyLedgerEra era)` (ledger PParams), so it's already compatible with the experimental API. The call site change is minimal — pass `era` directly instead of `convert ceo`.
## Notes
- The testnet infrastructure (`TestnetRuntime`, `createAndRunTestnet`, etc.) still uses `AnyShelleyBasedEra`, so `sbe = Exp.convert era` will still be needed for the testnet options. This is not part of this migration scope.
- Address deserialization from RPC responses (`deserialiseAddressBs`) uses old-API `AddressInEra`. These can either be kept (with `toShelleyAddr` conversion) or replaced with direct ledger address deserialization if available.
- The helper functions `txoRefToTxIn` and `deserialiseAddressBs` use old-API types (`TxIn`, `SerialiseAddress`) and can remain as-is since they're about deserialization, not tx building.
- Reference test for the experimental API pattern: `cardano-api/test/cardano-api-test/Test/Cardano/Api/Experimental.hs`
## Test plan
- [ ] Migrate the code following the steps above
- [ ] Build successfully with `cabal build cardano-testnet-test`
- [ ] Run the test: `TASTY_PATTERN='/RPC Transaction Submit/' cabal test cardano-testnet-test`
- [ ] Verify the transaction is still submitted and confirmed correctly via RPC
1 条评论