diff --git a/exercises/at_most_m_of_n.sh b/exercises/at_most_m_of_n.sh new file mode 100755 index 0000000..4e15bfa --- /dev/null +++ b/exercises/at_most_m_of_n.sh @@ -0,0 +1,28 @@ +#!/bin/bash +source ./tools/tb_function.sh + +tb "create_accounts id=10000 code=10 ledger=100, + id=10001 code=10 ledger=100, + id=1 code=10 ledger=1 flags=debits_must_not_exceed_credits, + id=2 code=10 ledger=1;" + +# Here, we want at most 2 of these transfers to succeed. +# We do that by making each real transfer transfer 1 unit on ledger 1 to an account whose balance is limited to 2. +output=$(tb "create_transfers id=1 debit_account_id=2 credit_account_id=1 amount=2 ledger=1 code=1, + + id=100002 debit_account_id=10000 credit_account_id=10001 amount=10 ledger=100 code=10 flags=linked, + id=2 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=1, + + id=100003 debit_account_id=10000 credit_account_id=0 amount=100 ledger=100 code=10 flags=linked, + id=3 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=1, + + id=100004 debit_account_id=10000 credit_account_id=10001 amount=1000 ledger=100 code=10 flags=linked, + id=4 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=1, + + id=100005 debit_account_id=10000 credit_account_id=10001 amount=10000 ledger=100 code=10 flags=linked, + id=5 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=1, + + id=6 debit_account_id=2 credit_account_id=1 amount=0 ledger=1 code=10 flags=balancing_credit;") +echo "$output" + +tb "lookup_accounts id=1, id=10000;" diff --git a/exercises/if_else.sh b/exercises/if_else.sh new file mode 100755 index 0000000..0547482 --- /dev/null +++ b/exercises/if_else.sh @@ -0,0 +1,21 @@ +#!/bin/bash +source ./tools/tb_function.sh + +tb "create_accounts id=10000 code=10 ledger=100 flags=debits_must_not_exceed_credits, + id=10001 code=10 ledger=100, + id=1 code=10 ledger=1, + id=2 code=10 ledger=1;" + +tb "create_transfers id=100001 debit_account_id=10001 credit_account_id=10000 amount=100 ledger=100 code=10;" + +# If amount > 100, the first two transfers will fail. +# If amount <= 100, the first two transfers will succeed and the third and fourth will fail. +# We're deliberately trying to create transfer 100000 in both branches with different codes. +AMOUNT=101 +tb "create_transfers id=100002 debit_account_id=10000 credit_account_id=10001 amount=$AMOUNT ledger=100 code=10 flags=linked, + id=100000 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=1, + + id=100003 debit_account_id=10000 credit_account_id=10001 amount=50 ledger=100 code=10 flags=linked, + id=100000 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=2;" + +tb "lookup_transfers id=100000;" diff --git a/exercises/if_then_multiple.sh b/exercises/if_then_multiple.sh new file mode 100755 index 0000000..fa9aa0b --- /dev/null +++ b/exercises/if_then_multiple.sh @@ -0,0 +1,46 @@ +#!/bin/bash +source ./tools/tb_function.sh + +# We can use the technique described in ./if_else.sh to execute a transfer +# if a condition is met. We can use the same technique to execute multiple transfers +# if that condition is met by using linked transfers. + +# However, our conditional set of transfers must ALL succeed in order for it to work. +# If one of them might fail, that technique is insufficient. + +# We can instead use the technique illustrated here to check a condition and, if it is met, +# execute a set of transfers where the success or failure of one does not affect the others. + +tb "create_accounts id=10000 code=10 ledger=100 flags=debits_must_not_exceed_credits, + id=10001 code=10 ledger=100, + id=1 code=10 ledger=1 flags=debits_must_not_exceed_credits, + id=2 code=10 ledger=1;" + +tb "create_transfers id=100000 debit_account_id=10001 credit_account_id=10000 amount=100 ledger=100 code=10;" + +# If amount > 100, all of the transfers will fail. +# If amount <= 100, the following events will happen: +# - Transfer 11 will succeed and set account 2's net credit balance to be 2. +# - Transfer 100003 will succeed, and transfer 13 will take 1 unit back from account 1 to account 2. +# - Transfer 100004 will fail, along with transfer 14, but this will not affect the others. +# - Transfer 100005 will succeed, and transfer 15 will take 1 unit back from account 1 to account 2. +# - Transfer 100006 and 16 will fail because account 1 no longer has a sufficient balance to transfer 1 unit. + +AMOUNT=101 # try changing this to 100 to make the set of transfers succeed +tb "create_transfers id=100001 debit_account_id=10000 credit_account_id=10001 amount=$AMOUNT ledger=100 code=10 flags=linked | pending, + id=100002 pending_id=100001 flags=linked | void_pending_transfer, + id=11 debit_account_id=2 credit_account_id=1 amount=2 ledger=1 code=10, + + id=13 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=10 flags=linked, + id=100003 debit_account_id=10000 credit_account_id=10001 amount=50 ledger=100 code=10, + + id=14 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=10 flags=linked, + id=100004 debit_account_id=10000 credit_account_id=10001 amount=99999 ledger=100 code=10, + + id=15 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=10 flags=linked, + id=100005 debit_account_id=10000 credit_account_id=10001 amount=50 ledger=100 code=10, + + id=16 debit_account_id=1 credit_account_id=2 amount=1 ledger=1 code=10 flags=linked, + id=100006 debit_account_id=10000 credit_account_id=10001 amount=50 ledger=100 code=10;" + +tb "lookup_transfers id=100003, id=100004, id=100005, id=100006;" diff --git a/exercises/pool_funds.sh b/exercises/pool_funds.sh new file mode 100755 index 0000000..2d79f62 --- /dev/null +++ b/exercises/pool_funds.sh @@ -0,0 +1,78 @@ +#!/bin/bash +source ./tools/tb_function.sh + +# This example shows how to pool a certain amount from multiple accounts to transfer to a single account. +# Note that it builds on the mechanisms introduced in ./if_then_multiple.sh + +OPERATOR_ACCOUNT=10000 +POOL_ACCOUNT=10001 +CHECK_ACCOUNT=10002 +ACCOUNT_1=10003 +ACCOUNT_2=10004 +TARGET_ACCOUNT=10005 +IF_ACCOUNT=10 +IF_OPERATOR=11 +tb "create_accounts id=$OPERATOR_ACCOUNT code=10 ledger=100, + id=$CHECK_ACCOUNT code=10 ledger=100 flags=credits_must_not_exceed_debits, + id=$POOL_ACCOUNT code=10 ledger=100, + id=$ACCOUNT_1 code=10 ledger=100 flags=debits_must_not_exceed_credits, + id=$ACCOUNT_2 code=10 ledger=100 flags=debits_must_not_exceed_credits, + id=$TARGET_ACCOUNT code=10 ledger=100 flags=debits_must_not_exceed_credits, + id=$IF_ACCOUNT code=10 ledger=1 flags=debits_must_not_exceed_credits, + id=$IF_OPERATOR code=10 ledger=1;" + +echo "funding accounts 1 and 2 with 100 units" + +# Now, we'll fund Accounts 1 and 2 with 100 units each. +tb "create_transfers id=1000 debit_account_id=$OPERATOR_ACCOUNT credit_account_id=$ACCOUNT_1 amount=100 ledger=100 code=10, + id=1001 debit_account_id=$OPERATOR_ACCOUNT credit_account_id=$ACCOUNT_2 amount=100 ledger=100 code=10;" + +# Now, we want to pool funds between ACCOUNT_1 and ACCOUNT_2 to transfer to TARGET_ACCOUNT. +POOL_AMOUNT=250 # Change this to 150 to make the transfers succeed. + +echo "pooling funds from accounts 1 and 2 to transfer to target account" + +# This looks very complicated, so let's go through each block of transfers. + +# The first block checks that the sum of the balances of ACCOUNT_1 and ACCOUNT_2 is greater than or equal to the POOL_AMOUNT. +# If they are, that whole first block of transfers will fail. + +# If the first block of transfers fails, the second block of transfers will succeed +# (because the transfer with id=10 intentionally appears in both the first and second blocks -- it will only succeed once). +# This block of transfers transfers 2 units to the IF_ACCOUNT +# AND it *DEBITS* the POOL_ACCOUNT by the POOL_AMOUNT. + +# The third and fourth blocks of transfers transfer *EXACTLY* the POOL_AMOUNT from ACCOUNT_1 and ACCOUNT_2 to the POOL_ACCOUNT. +# In each of these blocks, the first transfer (id=11 and id=12) take 1 unit from the IF_ACCOUNT +# (these would fail if the second block of transfers hadn't put 2 units in the IF_ACCOUNT). +# Then, they transfer (id=1009, id=1011) the lesser of the POOL_AMOUNT and the net credit balance of ACCOUNT_1 or ACCOUNT_2 to the POOL_ACCOUNT. +# Then, if the POOL_ACCOUNT now has a credit balance that is *GREATER* than the POOL_AMOUNT they transfer (id=1010, id=1012) the execess back to the account it came from. +# It is important that this last transfer in these blocks is *NOT* linked, because it will fail if the POOL_ACCOUNT's credit balance is less than or equal to the POOL_AMOUNT. + +# Finally, the last block of transfers transfers the POOL_AMOUNT from the POOL_ACCOUNT to the TARGET_ACCOUNT +# and resets the POOL_ACCOUNT's net balance back to 0. + +output=$(tb "create_transfers id=1002 debit_account_id=$CHECK_ACCOUNT credit_account_id=$OPERATOR_ACCOUNT amount=$((POOL_AMOUNT - 1)) ledger=100 code=10 flags=linked, + id=1003 debit_account_id=$ACCOUNT_1 credit_account_id=$CHECK_ACCOUNT amount=0 ledger=100 code=10 flags=linked | pending | balancing_debit, + id=1004 debit_account_id=$ACCOUNT_2 credit_account_id=$CHECK_ACCOUNT amount=0 ledger=100 code=10 flags=linked | pending | balancing_debit, + id=1005 pending_id=1003 code=10 flags=linked | void_pending_transfer, + id=1006 pending_id=1004 code=10 flags=linked | void_pending_transfer, + id=10 debit_account_id=$IF_OPERATOR credit_account_id=$IF_ACCOUNT amount=2 ledger=1 code=10 flags=linked | pending, + id=11 pending_id=10 code=10 flags=void_pending_transfer, + id=1007 debit_account_id=$OPERATOR_ACCOUNT credit_account_id=$CHECK_ACCOUNT amount=0 ledger=100 code=10 flags=balancing_credit, + + id=10 debit_account_id=$IF_OPERATOR credit_account_id=$IF_ACCOUNT amount=2 ledger=1 code=11 flags=linked, + id=1008 debit_account_id=$POOL_ACCOUNT credit_account_id=$OPERATOR_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10, + + id=11 debit_account_id=$IF_ACCOUNT credit_account_id=$IF_OPERATOR amount=1 ledger=1 code=10 flags=linked, + id=1009 debit_account_id=$ACCOUNT_1 credit_account_id=$POOL_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=balancing_debit, + id=1010 debit_account_id=$POOL_ACCOUNT credit_account_id=$ACCOUNT_1 amount=0 ledger=100 code=10 flags=balancing_debit, + + id=12 debit_account_id=$IF_ACCOUNT credit_account_id=$IF_OPERATOR amount=1 ledger=1 code=10 flags=linked, + id=1011 debit_account_id=$ACCOUNT_2 credit_account_id=$POOL_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=balancing_debit, + id=1012 debit_account_id=$POOL_ACCOUNT credit_account_id=$ACCOUNT_2 amount=0 ledger=100 code=10 flags=balancing_debit, + + id=1013 debit_account_id=$POOL_ACCOUNT credit_account_id=$TARGET_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=balancing_debit;") +echo "$output" + +tb "lookup_accounts id=$POOL_ACCOUNT, id=$CHECK_ACCOUNT, id=$ACCOUNT_1, id=$ACCOUNT_2, id=$TARGET_ACCOUNT;"