From 93639164ceacd3c0c5d5f758756ebde9111abe19 Mon Sep 17 00:00:00 2001 From: Evan Schwartz <3262610+emschwartz@users.noreply.github.com> Date: Wed, 26 Jun 2024 10:05:03 -0400 Subject: [PATCH 1/6] if / else --- exercises/if_else.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 exercises/if_else.sh 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;" From 6aa01e993b1a6f1dc65027fcd2134c561ade2357 Mon Sep 17 00:00:00 2001 From: Evan Schwartz <3262610+emschwartz@users.noreply.github.com> Date: Wed, 26 Jun 2024 10:05:09 -0400 Subject: [PATCH 2/6] at most m of n --- exercises/at_most_m_of_n.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 exercises/at_most_m_of_n.sh 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;" From cbe8581b6bd6d393db8987725b0cc0b906507ee3 Mon Sep 17 00:00:00 2001 From: Evan Schwartz <3262610+emschwartz@users.noreply.github.com> Date: Fri, 28 Jun 2024 10:20:42 -0400 Subject: [PATCH 3/6] add if then multiple --- exercises/if_then_multiple.sh | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100755 exercises/if_then_multiple.sh diff --git a/exercises/if_then_multiple.sh b/exercises/if_then_multiple.sh new file mode 100755 index 0000000..f028d83 --- /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, + id=2 code=10 ledger=1 flags=credits_must_not_exceed_debits;" + +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;" From 16d1fb7891de10e0404429677ab35f5df93f8bad Mon Sep 17 00:00:00 2001 From: Evan Schwartz <3262610+emschwartz@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:07:06 -0400 Subject: [PATCH 4/6] pool funds --- exercises/if_then_multiple.sh | 4 +- exercises/pool_funds.sh | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100755 exercises/pool_funds.sh diff --git a/exercises/if_then_multiple.sh b/exercises/if_then_multiple.sh index f028d83..fa9aa0b 100755 --- a/exercises/if_then_multiple.sh +++ b/exercises/if_then_multiple.sh @@ -13,8 +13,8 @@ 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 flags=credits_must_not_exceed_debits;" + 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;" diff --git a/exercises/pool_funds.sh b/exercises/pool_funds.sh new file mode 100755 index 0000000..27f055e --- /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=150 # 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=1008, id=1010) 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=1009, id=1011) 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=10 debit_account_id=$IF_OPERATOR credit_account_id=$IF_ACCOUNT amount=2 ledger=1 code=11 flags=linked, + id=1007 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=1008 debit_account_id=$ACCOUNT_1 credit_account_id=$POOL_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=balancing_debit, + id=1009 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=1010 debit_account_id=$ACCOUNT_2 credit_account_id=$POOL_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=balancing_debit, + id=1011 debit_account_id=$POOL_ACCOUNT credit_account_id=$ACCOUNT_2 amount=0 ledger=100 code=10 flags=balancing_debit, + + id=1012 debit_account_id=$POOL_ACCOUNT credit_account_id=$TARGET_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=linked, + id=1013 debit_account_id=$OPERATOR_ACCOUNT credit_account_id=$POOL_ACCOUNT amount=0 ledger=100 code=10 flags=balancing_credit;") +echo "$output" + +tb "lookup_accounts id=$POOL_ACCOUNT, id=$CHECK_ACCOUNT, id=$ACCOUNT_1, id=$ACCOUNT_2, id=$TARGET_ACCOUNT;" From 9b0b09fd137d23e996557ee0b38aa83902c4457d Mon Sep 17 00:00:00 2001 From: Evan Schwartz <3262610+emschwartz@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:16:24 -0400 Subject: [PATCH 5/6] fix case where accounts don't have the amount --- exercises/pool_funds.sh | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/exercises/pool_funds.sh b/exercises/pool_funds.sh index 27f055e..d7023c6 100755 --- a/exercises/pool_funds.sh +++ b/exercises/pool_funds.sh @@ -28,7 +28,7 @@ tb "create_transfers id=1000 debit_account_id=$OPERATOR_ACCOUNT credit_account_i 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=150 # Change this to 150 to make the transfers succeed. +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" @@ -45,8 +45,8 @@ echo "pooling funds from accounts 1 and 2 to transfer to target account" # 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=1008, id=1010) 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=1009, id=1011) the execess back to the account it came from. +# 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 @@ -59,20 +59,21 @@ output=$(tb "create_transfers id=1002 debit_account_id=$CHECK_ACCOUNT credit_acc 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=1007 debit_account_id=$POOL_ACCOUNT credit_account_id=$OPERATOR_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10, + 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=1008 debit_account_id=$ACCOUNT_1 credit_account_id=$POOL_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=balancing_debit, - id=1009 debit_account_id=$POOL_ACCOUNT credit_account_id=$ACCOUNT_1 amount=0 ledger=100 code=10 flags=balancing_debit, + 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=1010 debit_account_id=$ACCOUNT_2 credit_account_id=$POOL_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=balancing_debit, - id=1011 debit_account_id=$POOL_ACCOUNT credit_account_id=$ACCOUNT_2 amount=0 ledger=100 code=10 flags=balancing_debit, + 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=1012 debit_account_id=$POOL_ACCOUNT credit_account_id=$TARGET_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=linked, - id=1013 debit_account_id=$OPERATOR_ACCOUNT credit_account_id=$POOL_ACCOUNT amount=0 ledger=100 code=10 flags=balancing_credit;") + id=1013 debit_account_id=$POOL_ACCOUNT credit_account_id=$TARGET_ACCOUNT amount=$POOL_AMOUNT ledger=100 code=10 flags=balancing_debit;") + # id=1014 debit_account_id=$OPERATOR_ACCOUNT credit_account_id=$POOL_ACCOUNT amount=0 ledger=100 code=10 flags=balancing_credit;") echo "$output" tb "lookup_accounts id=$POOL_ACCOUNT, id=$CHECK_ACCOUNT, id=$ACCOUNT_1, id=$ACCOUNT_2, id=$TARGET_ACCOUNT;" From 12c6fc1781ab76dff582a653935b91e6c1dbb105 Mon Sep 17 00:00:00 2001 From: Evan Schwartz <3262610+emschwartz@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:14:50 -0400 Subject: [PATCH 6/6] remove unused transfer --- exercises/pool_funds.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/exercises/pool_funds.sh b/exercises/pool_funds.sh index d7023c6..2d79f62 100755 --- a/exercises/pool_funds.sh +++ b/exercises/pool_funds.sh @@ -73,7 +73,6 @@ output=$(tb "create_transfers id=1002 debit_account_id=$CHECK_ACCOUNT credit_acc 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;") - # id=1014 debit_account_id=$OPERATOR_ACCOUNT credit_account_id=$POOL_ACCOUNT amount=0 ledger=100 code=10 flags=balancing_credit;") echo "$output" tb "lookup_accounts id=$POOL_ACCOUNT, id=$CHECK_ACCOUNT, id=$ACCOUNT_1, id=$ACCOUNT_2, id=$TARGET_ACCOUNT;"