Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a faucet to distribute funds #227

Merged
merged 29 commits into from
Feb 25, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d277ec0
Replace postSeedPayment with seedFromFaucet in EndToEndSpec
ch1bo Feb 11, 2022
15d8772
Replace postSeedPayment with seedFromFaucet in DirectChainSpec
ch1bo Feb 11, 2022
1e14ef7
Distribute intial funds only to Faucet
ch1bo Feb 11, 2022
540e545
Import Hydra.Cardano.Api fully
ch1bo Feb 11, 2022
a0b3518
Fix compilation of hydra-cluster
ch1bo Feb 21, 2022
5698296
Send initial funds only to faucet and use it in seed-devnet.sh
ch1bo Feb 21, 2022
b8deebd
Remove seed-network executable and update instructions
ch1bo Feb 21, 2022
f3f0351
Remove generatePaymentToCommit and postSeedPayment
ch1bo Feb 21, 2022
350ae14
Remove setInitialFundsInGenesisShelley
ch1bo Feb 21, 2022
0ef2f19
Remove unused genesis verification keys
ch1bo Feb 21, 2022
b656ab4
Update LocalClusterSpec to use seedFromFaucet
ch1bo Feb 22, 2022
0c7efcc
Drop initialFunds from withBFTNode and withCluster
ch1bo Feb 23, 2022
93adc5a
Generalize mkGenesisTx to take many recipients
ch1bo Feb 23, 2022
d8ddfcc
Use mkGenesisTx to fund whole all clients
ch1bo Feb 23, 2022
1ce9abb
Update bench to use new Dataset type accordingly
ch1bo Feb 23, 2022
b614d5e
Debug benchmark with some outputs
ch1bo Feb 23, 2022
ac069dd
Wait for funding transaction to be confirmed before fuelling up the c…
ch1bo Feb 24, 2022
71295bb
Update TUISpec with latest withBFTNode changes
ch1bo Feb 24, 2022
02a0417
Remove debug outputs from benchmark
ch1bo Feb 24, 2022
61ea7f6
Only copy credentials if not yet existing
ch1bo Feb 24, 2022
6cd9bb2
Cleanup cardano-node socket file in case
ch1bo Feb 24, 2022
0ab0924
Only adjust Spend redeemers in TinyWallet
ch1bo Feb 24, 2022
6b12c82
Add queryUTxOWhole for debugging
ch1bo Feb 24, 2022
4bfcda4
Define a getFuelUTxO in our wallet and use it for seeding the initTx
ch1bo Feb 24, 2022
2bfd258
Get rid of unsafePerformIO
ch1bo Feb 24, 2022
b449406
Use "fuel" as marker argument in seed-devnet.sh
ch1bo Feb 25, 2022
27b1d7c
Use code instead of comments
ch1bo Feb 25, 2022
19d8f9e
Introduce seedFromFaucet_ and rename Marked -> Fuel
ch1bo Feb 25, 2022
e327adf
Fix redundant import
ch1bo Feb 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,24 +121,18 @@ In the current stage of development, Hydra nodes need a specially crafted set of

## With Docker

The included script `seed-devnet.sh` uses the `cardano-cli` in the already running `cardano-node` container to give Alice, Bob and Carol some "fuel" UTXO while the change can be used to commit to the Head (this is why amounts vary in the script).
The included script `seed-devnet.sh` uses the `cardano-cli` in the already running `cardano-node` container to give Alice, Bob and Carol some UTXO to commit and some "fuel" UTXO.

NOTE: There is nothing special about those transactions so one could any other Cardano client to create those transactions. This transaction must match the following characteristics:
* It must pay all its outputs to the key that's used by the Hydra Node's internal wallet, as defined by argument `--cardano-signing-key` of `hydra-node` executable,
* One of the outputs of the transaction must include datum hash `a654fb60d21c1fed48db2c320aa6df9737ec0204c0ba53b9b94a09fb40e757f3`.
* It must pay outputs to commit to the key that's used by the Hydra Node's internal wallet, as defined by argument `--cardano-signing-key` of `hydra-node` executable,
* One of the outputs must include datum hash `a654fb60d21c1fed48db2c320aa6df9737ec0204c0ba53b9b94a09fb40e757f3` as this is our "fuel" marker.

## Without Docker

To seed the network with those UTXO, posting a transaction, one can use the `seed-network` executable:
You can use the `seed-devnet.sh` script by passing it the path to a `cardano-cli` executable to use instead of having it using the docker container, e.g.

For example, to ensure Alice can commit some 1000 Ada and also that "her" node can pay for the Hydra transactions, run:

```
sudo chmod a+w devnet/ipc/node.socket
cabal run seed-network -- \
--node-socket devnet/ipc/node.socket \
--cardano-signing-key devnet/credentials/alice.sk \
--commit-amount 1000000000
``` sh
./seed-devnet.sh $(which cardano-cli)
```

# Running clients
Expand Down
72 changes: 47 additions & 25 deletions demo/seed-devnet.sh
Original file line number Diff line number Diff line change
@@ -1,42 +1,64 @@
#!/usr/bin/env bash

# Seed a "devnet" by marking some ADA as "payment outputs" for the Hydra Head
# ("the fuel tank").
# Seed a "devnet" by distributing some Ada to commit and also some marked as
# "fuel" for the Hydra Head.
set -e

TESTNET_MAGIC=42
MARKER_DATUM_HASH="a654fb60d21c1fed48db2c320aa6df9737ec0204c0ba53b9b94a09fb40e757f3"
DEVNET_FUNDS=900000000000
STANDARD_FEE=167393
SCRIPT_DIR=$(realpath $(dirname $(realpath $0)))

CCLI_PATH=
DEVNET_DIR=/data
if [[ -n ${1} ]] && $(${1} version > /dev/null); then
CCLI_PATH=${1}
echo >&2 "Using provided cardano-cli"
DEVNET_DIR=${SCRIPT_DIR}/devnet
fi

# Invoke cardano-cli in running cardano-node container or via provided cardano-cli
function ccli() {
# Invoke cardano-cli in running cardano-node container
docker-compose exec cardano-node cardano-cli ${@} --testnet-magic 42
if [[ -x ${CCLI_PATH} ]]; then
cardano-cli ${@} --testnet-magic 42
else
docker-compose exec cardano-node cardano-cli ${@} --testnet-magic 42
fi
}

function seedCommit() {
# Retrieve some lovelace from faucet, marked as "fuel" if requested
function seedFaucet() {
ACTOR=${1}
COMMIT_AMOUNT=${2}
FUEL_AMOUNT=$((${DEVNET_FUNDS}-${COMMIT_AMOUNT}-${STANDARD_FEE}))
echo >&2 "Seeding a commit UTXO for ${ACTOR} with ${COMMIT_AMOUNT}Ł (${FUEL_AMOUNT}Ł of fuel)"
AMOUNT=${2}
MARKED=${3:-"normal"}
echo >&2 "Seeding a UTXO from faucet to ${ACTOR} with ${AMOUNT}Ł (${MARKED})"

# Determine faucet address and just the **first** txin addressed to it
FAUCET_ADDR=$(ccli address build --payment-verification-key-file ${DEVNET_DIR}/credentials/faucet.vk)
FAUCET_TXIN=$(ccli query utxo --address ${FAUCET_ADDR} --out-file /dev/stdout | jq -r 'keys[0]')

ACTOR_ADDR=$(ccli address build --payment-verification-key-file ${DEVNET_DIR}/credentials/${ACTOR}.vk)

ADDR=$(ccli address build --payment-verification-key-file ${DEVNET_DIR}/credentials/${ACTOR}.vk)
GENESIS_TXIN=$(ccli genesis initial-txin --verification-key-file ${DEVNET_DIR}/credentials/${ACTOR}-genesis.vk | tr -d '\n\r')
# Optionally mark output
MARKER=""
if [[ "${MARKED}" == "fuel" ]]; then
MARKER="--tx-out-datum-hash ${MARKER_DATUM_HASH}"
fi

ccli transaction build --alonzo-era --cardano-mode \
--change-address ${ADDR} \
--tx-in ${GENESIS_TXIN} \
--tx-out ${ADDR}+${FUEL_AMOUNT} \
--tx-out-datum-hash ${MARKER_DATUM_HASH} \
--out-file ${DEVNET_DIR}/${ACTOR}.draft
--change-address ${FAUCET_ADDR} \
--tx-in ${FAUCET_TXIN} \
--tx-out ${ACTOR_ADDR}+${AMOUNT} \
${MARKER} \
--out-file ${DEVNET_DIR}/seed-${ACTOR}.draft
ccli transaction sign \
--tx-body-file ${DEVNET_DIR}/${ACTOR}.draft \
--signing-key-file ${DEVNET_DIR}/credentials/${ACTOR}.sk \
--out-file ${DEVNET_DIR}/${ACTOR}.signed
ccli transaction submit --tx-file ${DEVNET_DIR}/${ACTOR}.signed
--tx-body-file ${DEVNET_DIR}/seed-${ACTOR}.draft \
--signing-key-file ${DEVNET_DIR}/credentials/faucet.sk \
--out-file ${DEVNET_DIR}/seed-${ACTOR}.signed
ccli transaction submit --tx-file ${DEVNET_DIR}/seed-${ACTOR}.signed
}

seedCommit "alice" 1000000000
seedCommit "bob" 500000000
seedCommit "carol" 250000000
seedFaucet "alice" 1000000000 # 1000 Ada to commit
seedFaucet "alice" 100000000 "fuel" # 100 Ada marked as "fuel"
seedFaucet "bob" 500000000 # 500 Ada to commit
seedFaucet "bob" 100000000 "fuel" # 100 Ada marked as "fuel"
seedFaucet "carol" 250000000 # 250 Ada to commit
seedFaucet "carol" 100000000 "fuel" # 100 Ada marked as "fuel"
82 changes: 50 additions & 32 deletions hydra-cluster/bench/Bench/EndToEnd.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,14 @@ module Bench.EndToEnd where
import Hydra.Prelude
import Test.Hydra.Prelude

import qualified Cardano.Api.UTxO as UTxO
import Cardano.Crypto.DSIGN (
DSIGNAlgorithm (deriveVerKeyDSIGN),
MockDSIGN,
SignKeyDSIGN,
VerKeyDSIGN,
)
import CardanoClient (
submit,
waitForTransaction,
)
import CardanoCluster (defaultNetworkId, newNodeConfig, withBFTNode)
import CardanoClient (submit, waitForTransaction)
import CardanoCluster (Marked (Fuel), defaultNetworkId, newNodeConfig, seedFromFaucet, withBFTNode)
import CardanoNode (RunningNode (..))
import Control.Lens (to, (^?))
import Control.Monad.Class.MonadAsync (mapConcurrently)
Expand All @@ -41,7 +37,7 @@ import Data.Set ((\\))
import qualified Data.Set as Set
import Data.Time (UTCTime (UTCTime), nominalDiffTimeToSeconds, utctDayTime)
import Hydra.Cardano.Api (Tx, TxId, UTxO, getVerificationKey)
import Hydra.Generator (Dataset (..))
import Hydra.Generator (ClientDataset (..), Dataset (..))
import Hydra.Ledger (txId)
import Hydra.Logging (withTracerOutputTo)
import Hydra.Party (deriveParty, generateKey)
Expand Down Expand Up @@ -88,37 +84,42 @@ data Event = Event
}
deriving (Generic, Eq, Show, ToJSON)

bench :: DiffTime -> FilePath -> [Dataset] -> Word64 -> Spec
bench timeoutSeconds workDir dataset clusterSize =
bench :: DiffTime -> FilePath -> Dataset -> Word64 -> Spec
bench timeoutSeconds workDir dataset@Dataset{clientDatasets} clusterSize =
specify ("Load test on " <> show clusterSize <> " local nodes in " <> workDir) $ do
withFile (workDir </> "test.log") ReadWriteMode $ \hdl ->
withTracerOutputTo hdl "Test" $ \tracer ->
failAfter timeoutSeconds $ do
let cardanoKeys = map (\Dataset{signingKey} -> (getVerificationKey signingKey, signingKey)) dataset
putTextLn "Starting benchmark"
let cardanoKeys = map (\ClientDataset{signingKey} -> (getVerificationKey signingKey, signingKey)) clientDatasets
let hydraKeys = generateKey <$> [1 .. toInteger (length cardanoKeys)]
let parties = Set.fromList (deriveParty <$> hydraKeys)
config <- newNodeConfig workDir
withOSStats workDir $
withBFTNode (contramap FromCluster tracer) config (fst <$> cardanoKeys) $ \(RunningNode _ nodeSocket) -> do
withHydraCluster tracer workDir nodeSocket 1 cardanoKeys hydraKeys $ \(leader :| followers) -> do
let nodes = leader : followers
waitForNodesConnected tracer nodes
withBFTNode (contramap FromCluster tracer) config $ \node@(RunningNode _ nodeSocket) -> do
withHydraCluster tracer workDir nodeSocket 0 cardanoKeys hydraKeys $ \(leader :| followers) -> do
let clients = leader : followers
waitForNodesConnected tracer clients

initialUTxOs <- createUTxOToCommit dataset nodeSocket
putTextLn "Seeding network"
seedNetwork node dataset

putTextLn "Initializing Head"
let contestationPeriod = 10 :: Natural
send leader $ input "Init" ["contestationPeriod" .= contestationPeriod]
waitFor tracer (fromIntegral $ 10 * clusterSize) nodes $
waitFor tracer (fromIntegral $ 10 * clusterSize) clients $
output "ReadyToCommit" ["parties" .= parties]

expectedUTxO <- mconcat <$> forM (zip nodes initialUTxOs) (uncurry commit)
putTextLn "Comitting initialUTxO from dataset"
expectedUTxO <- commitUTxO clients dataset

waitFor tracer (fromIntegral $ 10 * clusterSize) nodes $
waitFor tracer (fromIntegral $ 10 * clusterSize) clients $
output "HeadIsOpen" ["utxo" .= expectedUTxO]

processedTransactions <- processTransactions nodes dataset
putTextLn "HeadIsOpen"
processedTransactions <- processTransactions clients dataset

putTextLn "Closing the Head..."
putTextLn "Closing the Head"
send leader $ input "Close" []
waitMatch (fromIntegral $ 60 * clusterSize) leader $ \v ->
guard (v ^? key "tag" == Just "HeadIsFinalized")
Expand Down Expand Up @@ -218,25 +219,42 @@ movingAverage confirmations =
)
in map average fiveSeconds

createUTxOToCommit :: [Dataset] -> FilePath -> IO [UTxO]
createUTxOToCommit dataset nodeSocket =
forM dataset $ \Dataset{fundingTransaction} -> do
-- | Distribute 100 ADA fuel and starting funds from faucet for each client in
-- the dataset.
seedNetwork :: RunningNode -> Dataset -> IO ()
seedNetwork node@(RunningNode _ nodeSocket) Dataset{fundingTransaction, clientDatasets} = do
fundClients
forM_ clientDatasets fuelWith100Ada
where
fundClients = do
submit defaultNetworkId nodeSocket fundingTransaction
UTxO.min <$> waitForTransaction defaultNetworkId nodeSocket fundingTransaction
void $ waitForTransaction defaultNetworkId nodeSocket fundingTransaction

fuelWith100Ada ClientDataset{signingKey} = do
let vk = getVerificationKey signingKey
seedFromFaucet defaultNetworkId node vk 100_000_000 Fuel

-- | Commit all (expected to exit) 'initialUTxO' from the dataset using the
-- (asumed same sequence) of clients.
commitUTxO :: [HydraClient] -> Dataset -> IO UTxO
commitUTxO clients Dataset{clientDatasets} =
mconcat <$> forM (zip clients clientDatasets) doCommit
where
doCommit (client, ClientDataset{initialUTxO}) = commit client initialUTxO

processTransactions :: [HydraClient] -> [Dataset] -> IO (Map.Map TxId Event)
processTransactions clients dataset = do
let processors = zip (zip dataset (cycle clients)) [1 ..]
mconcat <$> mapConcurrently (uncurry clientProcessTransactionsSequence) processors
processTransactions :: [HydraClient] -> Dataset -> IO (Map.Map TxId Event)
processTransactions clients Dataset{clientDatasets} = do
let processors = zip (zip clientDatasets (cycle clients)) [1 ..]
mconcat <$> mapConcurrently (uncurry clientProcessDataset) processors
where
clientProcessTransactionsSequence (Dataset{transactionsSequence}, client) clientId = do
let numberOfTxs = length transactionsSequence
clientProcessDataset (ClientDataset{txSequence}, client) clientId = do
let numberOfTxs = length txSequence
submissionQ <- newTBQueueIO (fromIntegral numberOfTxs)
registry <- newRegistry
withNewClient client $ \client' -> do
atomically $ forM_ transactionsSequence $ writeTBQueue submissionQ
atomically $ forM_ txSequence $ writeTBQueue submissionQ
submitTxs client' registry submissionQ
`concurrently_` waitForAllConfirmations client' registry submissionQ (Set.fromList $ map txId transactionsSequence)
`concurrently_` waitForAllConfirmations client' registry submissionQ (Set.fromList $ map txId txSequence)
`concurrently_` progressReport (hydraNodeId client') clientId numberOfTxs submissionQ
readTVarIO (processedTxs registry)

Expand Down
2 changes: 1 addition & 1 deletion hydra-cluster/bench/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ main =
Left err -> fail $ show err
Right shelleyGenesis ->
pure $ fromLedgerPParams ShelleyBasedEraShelley (sgProtocolParams shelleyGenesis)
dataset <- replicateM (fromIntegral clusterSize) (generateConstantUTxODataset pparams numberOfTxs)
dataset <- generateConstantUTxODataset pparams (fromIntegral clusterSize) numberOfTxs
saveDataset benchDir dataset
run timeoutSeconds benchDir dataset clusterSize

Expand Down
5 changes: 0 additions & 5 deletions hydra-cluster/config/credentials/alice-genesis.vk

This file was deleted.

5 changes: 0 additions & 5 deletions hydra-cluster/config/credentials/bob-genesis.vk

This file was deleted.

5 changes: 0 additions & 5 deletions hydra-cluster/config/credentials/carol-genesis.vk

This file was deleted.

4 changes: 1 addition & 3 deletions hydra-cluster/config/genesis-shelley.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@
"updateQuorum": 5,
"networkId": "Testnet",
"initialFunds": {
"60f8a68cd18e59a6ace848155a0e967af64f4d00cf8acee8adc95a6b0d": 900000000000,
"601052386136b347f3bb7c67fe3f2ee4ef120e1836e5d2707bb068afa6": 900000000000,
"603aaa2e3de913b0f5aa7e7f076e122d737db5329df1aa905192284fea": 900000000000
"609783be7d3c54f11377966dfabc9284cd6c32fca1cd42ef0a4f1cc45b": 900000000000
},
"maxLovelaceSupply": 300,
"networkMagic": 42,
Expand Down
88 changes: 0 additions & 88 deletions hydra-cluster/exe/seed-network.hs

This file was deleted.

Loading