Skip to content

Commit

Permalink
Merge pull request #1268 from Plutonomicon/dshuiski/1131-multi-asset-…
Browse files Browse the repository at this point in the history
…coin-selection

Switch to multi-asset coin selection algorithm
  • Loading branch information
klntsky committed Feb 6, 2023
2 parents 5dcd9ac + b07455b commit 1af2bfc
Show file tree
Hide file tree
Showing 38 changed files with 3,052 additions and 535 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Expand Up @@ -7,7 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Unreleased](#unreleased)
- [[Unreleased]](#unreleased)
- [Added](#added)
- [Changed](#changed)
- [Removed](#removed)
Expand Down Expand Up @@ -43,15 +43,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Unreleased
## [Unreleased]

### Added

- `blake2b224Hash` and `blake2b224HashHex` functions for computing blake2b-224 hashes of arbitrary byte arrays ([#1323](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1323))
- `bundlePursProject` allows passing of `includeBundledModule` flag to export the bundled JS module `spago bundle-module` outputs

- `Contract.Transaction` exports `mkPoolPubKeyHash` and `poolPubKeyHashToBech32` for bech32 roundtripping ([#1360](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1360))

### Changed
- Balancer no longer selects UTxOs which use PlutusV2 features when the transaction contains PlutusV1 scripts ([#1349](https://github.com/Plutonomicon/cardano-transaction-lib/issues/1349))

- `startPlutipCluster` error message now includes cluster startup failure details. ([#1407](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1407))

Expand Down
4 changes: 2 additions & 2 deletions doc/faq.md
Expand Up @@ -10,7 +10,7 @@ This document lists common problems encountered by CTL users and developers.
- [Q: `lib.something` is not a function, why?](#q-libsomething-is-not-a-function-why)
- [Q: I see `spago: Error: Remote host not found`, why?](#q-i-see-spago-error-remote-host-not-found-why)
- [Common Contract execution problems](#common-contract-execution-problems)
- [Q: What are the common reasons behind InsufficientTxInputs error?](#q-what-are-the-common-reasons-behind-insufficienttxinputs-error)
- [Q: What are the common reasons behind BalanceInsufficientError?](#q-what-are-the-common-reasons-behind-balanceinsufficienterror)
- [Time-related](#time-related)
- [Q: Time-related functions behave strangely, what's the reason?](#q-time-related-functions-behave-strangely-whats-the-reason)
- [Q: Time/slot conversion functions return `Nothing`. Why is that?](#q-timeslot-conversion-functions-return-nothing-why-is-that)
Expand Down Expand Up @@ -48,7 +48,7 @@ means that the CTL overlay hasn't been properly applied. Add `ctl.overlays.spago

## Common Contract execution problems

### Q: What are the common reasons behind InsufficientTxInputs error?
### Q: What are the common reasons behind BalanceInsufficientError?

Most contracts require at least two UTxOs to run (one will be used as a collateral). If you use a wallet with only one UTxO, e.g. a new wallet you just funded from the faucet, you need to send yourself at least 5 tAda to create another UTxO for the collateral.

Expand Down
31 changes: 17 additions & 14 deletions examples/ECDSA.purs
Expand Up @@ -54,8 +54,7 @@ instance ToData ECDSARedemeer where

contract :: Contract () Unit
contract = do
void prepTest
void testECDSA
void $ prepTest >>= testECDSA

-- | Prepare the ECDSA test by locking some funds at the validator address
prepTest :: Contract () TransactionHash
Expand All @@ -81,8 +80,9 @@ prepTest = do
pure txId

-- | Attempt to unlock one utxo using an ECDSA signature
testVerification :: ECDSARedemeer -> Contract () TransactionHash
testVerification ecdsaRed = do
testVerification
:: TransactionHash -> ECDSARedemeer -> Contract () TransactionHash
testVerification txId ecdsaRed = do
let red = Redeemer $ toData ecdsaRed

validator <- liftContractM "Can't get validator" getValidator
Expand All @@ -94,31 +94,34 @@ testVerification ecdsaRed = do

scriptUtxos <- utxosAt valAddr
txIn <- liftContractM "No UTxOs found at validator address"
$ Set.findMin
$ Set.toUnfoldable
$ Set.filter (unwrap >>> _.transactionId >>> eq txId)
$ Map.keys scriptUtxos

let
lookups :: Lookups.ScriptLookups Void
lookups = Lookups.validator validator
<> Lookups.unspentOutputs scriptUtxos
<> Lookups.unspentOutputs
(Map.filterKeys ((unwrap >>> _.transactionId >>> eq txId)) scriptUtxos)

constraints :: Constraints.TxConstraints Void Void
constraints = Constraints.mustSpendScriptOutput txIn red
txId <- submitTxFromConstraints lookups constraints
logInfo' $ "Submitted ECDSA test verification tx: " <> show txId
awaitTxConfirmed txId
logInfo' $ "Transaction confirmed: " <> show txId
pure txId
txId' <- submitTxFromConstraints lookups constraints
logInfo' $ "Submitted ECDSA test verification tx: " <> show txId'
awaitTxConfirmed txId'
logInfo' $ "Transaction confirmed: " <> show txId'
pure txId'

-- | Testing ECDSA verification function on-chain
testECDSA :: Contract () TransactionHash
testECDSA = do
testECDSA :: TransactionHash -> Contract () TransactionHash
testECDSA txId = do
privateKey <- liftEffect $ randomSecp256k1PrivateKey
let
publicKey = deriveEcdsaSecp256k1PublicKey privateKey
message = byteArrayFromIntArrayUnsafe [ 0, 1, 2, 3 ]
messageHash <- liftAff $ hashMessageSha256 message
signature <- liftAff $ signEcdsaSecp256k1 privateKey messageHash
testVerification $
testVerification txId $
ECDSARedemeer
{ msg: messageHash
, sig: signature
Expand Down
31 changes: 17 additions & 14 deletions examples/Schnorr.purs
Expand Up @@ -50,8 +50,7 @@ instance ToData SchnorrRedeemer where

contract :: Contract () Unit
contract = do
void prepTest
void testSchnorr
void $ prepTest >>= testSchnorr

-- | Prepare the ECDSA test by locking some funds at the validator address
prepTest :: Contract () TransactionHash
Expand All @@ -76,8 +75,9 @@ prepTest = do
pure txId

-- | Attempt to unlock one utxo using an ECDSA signature
testVerification :: SchnorrRedeemer -> Contract () TransactionHash
testVerification ecdsaRed = do
testVerification
:: TransactionHash -> SchnorrRedeemer -> Contract () TransactionHash
testVerification txId ecdsaRed = do
let red = Redeemer $ toData ecdsaRed

validator <- liftContractM "Can't get validator" getValidator
Expand All @@ -89,30 +89,33 @@ testVerification ecdsaRed = do

scriptUtxos <- utxosAt valAddr
txIn <- liftContractM "No UTxOs found at validator address"
$ Set.findMin
$ Set.toUnfoldable
$ Set.filter (unwrap >>> _.transactionId >>> eq txId)
$ Map.keys scriptUtxos

let
lookups :: Lookups.ScriptLookups Void
lookups = Lookups.validator validator
<> Lookups.unspentOutputs scriptUtxos
<> Lookups.unspentOutputs
(Map.filterKeys ((unwrap >>> _.transactionId >>> eq txId)) scriptUtxos)

constraints :: Constraints.TxConstraints Void Void
constraints = Constraints.mustSpendScriptOutput txIn red
txId <- submitTxFromConstraints lookups constraints
logInfo' $ "Submitted Schnorr test verification tx: " <> show txId
awaitTxConfirmed txId
logInfo' $ "Transaction confirmed: " <> show txId
pure txId
txId' <- submitTxFromConstraints lookups constraints
logInfo' $ "Submitted Schnorr test verification tx: " <> show txId'
awaitTxConfirmed txId'
logInfo' $ "Transaction confirmed: " <> show txId'
pure txId'

-- | Testing ECDSA verification function on-chain
testSchnorr :: Contract () TransactionHash
testSchnorr = do
testSchnorr :: TransactionHash -> Contract () TransactionHash
testSchnorr txId = do
privateKey <- liftEffect $ randomSecp256k1PrivateKey
let
publicKey = deriveSchnorrSecp256k1PublicKey privateKey
message = byteArrayFromIntArrayUnsafe [ 0, 1, 2, 3 ]
signature <- liftAff $ signSchnorrSecp256k1 privateKey message
testVerification $
testVerification txId $
SchnorrRedeemer
{ msg: message
, sig: signature
Expand Down
22 changes: 11 additions & 11 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion nix/default.nix
Expand Up @@ -25,7 +25,7 @@
let
inherit (pkgs) system;

purs = pkgs.easy-ps.purs-0_14_5;
purs = pkgs.easy-ps.purs-0_14_9;

spagoPkgs = import spagoPackages { inherit pkgs; };

Expand Down
1 change: 1 addition & 0 deletions spago.dhall
Expand Up @@ -70,6 +70,7 @@ You can edit this file as you like.
, "quickcheck"
, "quickcheck-combinators"
, "quickcheck-laws"
, "random"
, "rationals"
, "record"
, "refs"
Expand Down
1 change: 1 addition & 0 deletions src/Contract/BalanceTxConstraints.purs
Expand Up @@ -9,6 +9,7 @@ import Ctl.Internal.BalanceTx.Constraints
, mustNotSpendUtxosWithOutRefs
, mustSendChangeToAddress
, mustUseAdditionalUtxos
, mustUseCoinSelectionStrategy
, mustUseUtxosAtAddress
, mustUseUtxosAtAddresses
) as BalanceTxConstraints
4 changes: 3 additions & 1 deletion src/Contract/Hashing.purs
Expand Up @@ -4,7 +4,9 @@ module Contract.Hashing

import Contract.Scripts (plutusScriptStakeValidatorHash) as X
import Ctl.Internal.Hashing
( blake2b256Hash
( blake2b224Hash
, blake2b224HashHex
, blake2b256Hash
, blake2b256HashHex
, datumHash
, plutusScriptHash
Expand Down
24 changes: 22 additions & 2 deletions src/Contract/Transaction.purs
Expand Up @@ -60,11 +60,30 @@ import Contract.TxConstraints (TxConstraints)
import Control.Monad.Error.Class (catchError, throwError)
import Control.Monad.Reader (ReaderT, asks, runReaderT)
import Control.Monad.Reader.Class (ask)
import Ctl.Internal.BalanceTx (BalanceTxError) as BalanceTxError
import Ctl.Internal.BalanceTx (FinalizedTransaction)
import Ctl.Internal.BalanceTx (FinalizedTransaction(FinalizedTransaction)) as FinalizedTransaction
import Ctl.Internal.BalanceTx (balanceTxWithConstraints) as BalanceTx
import Ctl.Internal.BalanceTx.Constraints (BalanceTxConstraintsBuilder)
import Ctl.Internal.BalanceTx.Error
( Actual(Actual)
, BalanceTxError
( BalanceInsufficientError
, CouldNotConvertScriptOutputToTxInput
, CouldNotGetChangeAddress
, CouldNotGetCollateral
, CouldNotGetUtxos
, CollateralReturnError
, CollateralReturnMinAdaValueCalcError
, ExUnitsEvaluationFailed
, InsufficientUtxoBalanceToCoverAsset
, ReindexRedeemersError
, UtxoLookupFailedFor
, UtxoMinAdaValueCalculationFailed
)
, Expected(Expected)
, ImpossibleError(Impossible)
, InvalidInContext(InvalidInContext)
) as BalanceTxError
import Ctl.Internal.Cardano.Types.NativeScript
( NativeScript
( ScriptPubkey
Expand Down Expand Up @@ -523,7 +542,8 @@ reindexSpentScriptRedeemers
(Array Transaction.Redeemer)
)
reindexSpentScriptRedeemers balancedTx =
wrapContract <<< ReindexRedeemers.reindexSpentScriptRedeemers balancedTx
wrapContract <<< pure <<< ReindexRedeemers.reindexSpentScriptRedeemers
balancedTx

newtype BalancedSignedTransaction = BalancedSignedTransaction Transaction

Expand Down

0 comments on commit 1af2bfc

Please sign in to comment.