From 9379d7465439b31178be9960d9fbbc4bfb6f0c28 Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Fri, 3 Feb 2023 10:17:55 +0100 Subject: [PATCH 1/9] add total_bonds variable --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index 8b3a4b1..38aae7c 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -22,6 +22,7 @@ type Validator struct { state map total_deltas map total_unbonds map + total_bonds map voting_power map reward_address Addr jail_record JailRecord @@ -230,6 +231,7 @@ func bond(validator_address, delegator_address, amount) //debit amount from delegator account and credit it to the PoS account balances[delegator_address] -= amount balances[pos] += amount + validators[validator_address].total_bonds[cur_epoch+pipeline_length] += amount update_total_deltas(validator_address, pipeline_lenght, amount) update_voting_power(validator_address, pipeline_lenght) update_total_voting_power(pipeline_lenght) @@ -497,15 +499,18 @@ end_of_epoch() var total_staked = read_epoched_field(validators[validator_address].total_deltas, slash.epoch, 0) var total_unbonded = 0 + var total_bonded = 0 //find the total unbonded from the slash epoch up to the current epoch first //a..b notation determines an integer range: all integers between a and b inclusive forall (epoch in slash.epoch+1..cur_epoch) do total_unbonded += validators[validator_address].total_unbonded[epoch] + total_bonded += validators[validator_address].total_bonded[epoch] var last_slash = 0 forall (offset in 1..unbonding_length) do total_unbonded += validators[validator_address].total_unbonded[cur_epoch + offset] - var this_slash = (total_staked - total_unbonded) * slash.rate + total_bonded += validators[validator_address].total_bonded[cur_epoch + offset] + var this_slash = (total_staked + total_bonded - total_unbonded) * slash.rate var diff_slashed_amount = last_slash - this_slash last_slash = this_slash update_total_deltas(validator_address, offset, diff_slashed_amount) From 1f9b3be091e0c9be517df76eb82cec838cd36659 Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Thu, 9 Feb 2023 15:58:47 +0100 Subject: [PATCH 2/9] fix for the issue --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index 38aae7c..bc2ae25 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -17,12 +17,16 @@ type JailRecord struct { epoch Epoch } +type UnbondRecord struct { + amount uint + start Epoch +} + type Validator struct { consensus_key map state map total_deltas map total_unbonds map - total_bonds map voting_power map reward_address Addr jail_record JailRecord @@ -231,7 +235,6 @@ func bond(validator_address, delegator_address, amount) //debit amount from delegator account and credit it to the PoS account balances[delegator_address] -= amount balances[pos] += amount - validators[validator_address].total_bonds[cur_epoch+pipeline_length] += amount update_total_deltas(validator_address, pipeline_lenght, amount) update_voting_power(validator_address, pipeline_lenght) update_total_voting_power(pipeline_lenght) @@ -274,14 +277,15 @@ func unbond(validator_address, delegator_address, unbond_amount) remain = 0 forall (slash in slashes[validator_address] s.t. start <= slash.epoch) amount_after_slashing -= remain*slash.rate + validators[validator_address].total_unbonds[cur_epoch+pipeline_length] = {UnbondRecord{amount: remain, start: start}} \union validators[validator_address].total_unbonds[cur_epoch+pipeline_length] //If the remaining is greater or equal than the next bond amount else if amount <= remain && remain > 0 do bonds[delegator_address][validator_address].deltas[start] = 0 unbonds[delegator_address][validator_address].deltas[start, cur_epoch+pipeline_length+unbonding_length] = amount remain -= amount + validators[validator_address].total_unbonds[cur_epoch+pipeline_length] = {UnbondRecord{amount: amount, start: start}} \union validators[validator_address].total_unbonds[cur_epoch+pipeline_length] forall (slash in slashes[validator_address] s.t. start <= slash.epoch) amount_after_slashing -= amount*slash.rate - validators[validator_address].total_unbonds[cur_epoch+pipeline_length] += unbond_amount update_total_deltas(validator_address, pipeline_length, -1*amount_after_slashing) update_voting_power(validator_address, pipeline_length) update_total_voting_power(pipeline_length) @@ -503,13 +507,13 @@ end_of_epoch() //find the total unbonded from the slash epoch up to the current epoch first //a..b notation determines an integer range: all integers between a and b inclusive forall (epoch in slash.epoch+1..cur_epoch) do - total_unbonded += validators[validator_address].total_unbonded[epoch] - total_bonded += validators[validator_address].total_bonded[epoch] + forall (unbond in validators[validator_address].total_unbonded[epoch] s.t. unbond.start <= slash.epoch) + total_unbonded += unbond.amount var last_slash = 0 forall (offset in 1..unbonding_length) do - total_unbonded += validators[validator_address].total_unbonded[cur_epoch + offset] - total_bonded += validators[validator_address].total_bonded[cur_epoch + offset] + forall (unbond in validators[validator_address].total_unbonded[epoch] s.t. unbond.start <= slash.epoch) + total_unbonded += unbond.amount var this_slash = (total_staked + total_bonded - total_unbonded) * slash.rate var diff_slashed_amount = last_slash - this_slash last_slash = this_slash From c962a895b9cbdd4339f3211c1a6a72e5d5a26c13 Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Thu, 9 Feb 2023 16:26:37 +0100 Subject: [PATCH 3/9] Update 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 1 - 1 file changed, 1 deletion(-) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index bc2ae25..eff5950 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -503,7 +503,6 @@ end_of_epoch() var total_staked = read_epoched_field(validators[validator_address].total_deltas, slash.epoch, 0) var total_unbonded = 0 - var total_bonded = 0 //find the total unbonded from the slash epoch up to the current epoch first //a..b notation determines an integer range: all integers between a and b inclusive forall (epoch in slash.epoch+1..cur_epoch) do From 57d13d9713df70a67eb93bb83ed65657a3c15dee Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Thu, 9 Feb 2023 16:27:40 +0100 Subject: [PATCH 4/9] Update 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index eff5950..b0451db 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -513,7 +513,7 @@ end_of_epoch() forall (offset in 1..unbonding_length) do forall (unbond in validators[validator_address].total_unbonded[epoch] s.t. unbond.start <= slash.epoch) total_unbonded += unbond.amount - var this_slash = (total_staked + total_bonded - total_unbonded) * slash.rate + var this_slash = (total_staked - total_unbonded) * slash.rate var diff_slashed_amount = last_slash - this_slash last_slash = this_slash update_total_deltas(validator_address, offset, diff_slashed_amount) From e1e80227e9b6c49ddbec63e746dcc659bf1b039e Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Thu, 9 Feb 2023 16:57:09 +0100 Subject: [PATCH 5/9] add comment corner case --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index b0451db..dbd07f0 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -277,7 +277,15 @@ func unbond(validator_address, delegator_address, unbond_amount) remain = 0 forall (slash in slashes[validator_address] s.t. start <= slash.epoch) amount_after_slashing -= remain*slash.rate - validators[validator_address].total_unbonds[cur_epoch+pipeline_length] = {UnbondRecord{amount: remain, start: start}} \union validators[validator_address].total_unbonds[cur_epoch+pipeline_length] + //The current model disregards a corner case that should be taken care of in the implementation: + //- Assume a user delegates 10 tokens to a validator at epoch e1 + //- Assume the user unbonds twice 5 tokens from the same validator in the same epoch in two different transactions e2 + //- When executing the first undelegate tx, the model creates the record UnbondRecord{amount: 5, start: e1 } and updates the bond to 5 tokens + //- When executing the second undelegate tx, the model creates the same record UnbondRecord{amount: 5, start: e1 } and removes the bond. + //- The problem is that we keep unbond records in a set and when we try to add the second record, since it is a duplicate, it will be discarded. + //It is an easy fix I'd say: use a bag instead of a set to allow duplicates, or check if the set includes the record and act upon (remove it, create a new one with double the amount, and add it). + //Same below + validators[validator_address].total_unbonds[cur_epoch+pipeline_length] = {UnbondRecord{amount: remain, start: start}} \union validators[validator_address].total_unbonds[cur_epoch+pipeline_length] //If the remaining is greater or equal than the next bond amount else if amount <= remain && remain > 0 do bonds[delegator_address][validator_address].deltas[start] = 0 From e5c643d43855a568a72e035424e00c0fd01dbe99 Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Thu, 9 Feb 2023 16:59:13 +0100 Subject: [PATCH 6/9] update --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index dbd07f0..d300ef8 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -280,8 +280,8 @@ func unbond(validator_address, delegator_address, unbond_amount) //The current model disregards a corner case that should be taken care of in the implementation: //- Assume a user delegates 10 tokens to a validator at epoch e1 //- Assume the user unbonds twice 5 tokens from the same validator in the same epoch in two different transactions e2 - //- When executing the first undelegate tx, the model creates the record UnbondRecord{amount: 5, start: e1 } and updates the bond to 5 tokens - //- When executing the second undelegate tx, the model creates the same record UnbondRecord{amount: 5, start: e1 } and removes the bond. + //- When executing the first undelegate tx, the model creates the record UnbondRecord{amount: 5, start: e1} and updates the bond to 5 tokens + //- When executing the second undelegate tx, the model creates the same record UnbondRecord{amount: 5, start: e1} and removes the bond. //- The problem is that we keep unbond records in a set and when we try to add the second record, since it is a duplicate, it will be discarded. //It is an easy fix I'd say: use a bag instead of a set to allow duplicates, or check if the set includes the record and act upon (remove it, create a new one with double the amount, and add it). //Same below From dff3ad8465b76639c134c80d7c2b87b3569eb6a0 Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Fri, 10 Feb 2023 09:52:08 +0100 Subject: [PATCH 7/9] fix remain=0 --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index d300ef8..312915a 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -274,7 +274,6 @@ func unbond(validator_address, delegator_address, unbond_amount) if amount > remain && remain > 0 do bonds[delegator_address][validator_address].deltas[start] = amount - remain unbonds[delegator_address][validator_address].deltas[start, cur_epoch+pipeline_length+unbonding_length] = remain - remain = 0 forall (slash in slashes[validator_address] s.t. start <= slash.epoch) amount_after_slashing -= remain*slash.rate //The current model disregards a corner case that should be taken care of in the implementation: @@ -286,14 +285,15 @@ func unbond(validator_address, delegator_address, unbond_amount) //It is an easy fix I'd say: use a bag instead of a set to allow duplicates, or check if the set includes the record and act upon (remove it, create a new one with double the amount, and add it). //Same below validators[validator_address].total_unbonds[cur_epoch+pipeline_length] = {UnbondRecord{amount: remain, start: start}} \union validators[validator_address].total_unbonds[cur_epoch+pipeline_length] + remain = 0 //If the remaining is greater or equal than the next bond amount else if amount <= remain && remain > 0 do bonds[delegator_address][validator_address].deltas[start] = 0 unbonds[delegator_address][validator_address].deltas[start, cur_epoch+pipeline_length+unbonding_length] = amount - remain -= amount validators[validator_address].total_unbonds[cur_epoch+pipeline_length] = {UnbondRecord{amount: amount, start: start}} \union validators[validator_address].total_unbonds[cur_epoch+pipeline_length] forall (slash in slashes[validator_address] s.t. start <= slash.epoch) amount_after_slashing -= amount*slash.rate + remain -= amount update_total_deltas(validator_address, pipeline_length, -1*amount_after_slashing) update_voting_power(validator_address, pipeline_length) update_total_voting_power(pipeline_length) From d83d8a4c6d5655ce8e9a2c9c2cfb30bf76dafb51 Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Mon, 13 Feb 2023 12:28:17 +0100 Subject: [PATCH 8/9] minor update --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index 312915a..06a1f8f 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -22,6 +22,11 @@ type UnbondRecord struct { start Epoch } +type SlashedAmount struct { + epoch Epoch + amount uint +} + type Validator struct { consensus_key map state map From 99bcd933650b3a566407a565d0ba3cb4384f85de Mon Sep 17 00:00:00 2001 From: Manuel Bravo Date: Wed, 15 Feb 2023 13:29:07 +0100 Subject: [PATCH 9/9] fix typos --- 2022/Q4/artifacts/PoS-pseudocode/PoS-model.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md index 06a1f8f..664c27d 100644 --- a/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md +++ b/2022/Q4/artifacts/PoS-pseudocode/PoS-model.md @@ -31,7 +31,7 @@ type Validator struct { consensus_key map state map total_deltas map - total_unbonds map + total_unbonds map> voting_power map reward_address Addr jail_record JailRecord @@ -519,12 +519,12 @@ end_of_epoch() //find the total unbonded from the slash epoch up to the current epoch first //a..b notation determines an integer range: all integers between a and b inclusive forall (epoch in slash.epoch+1..cur_epoch) do - forall (unbond in validators[validator_address].total_unbonded[epoch] s.t. unbond.start <= slash.epoch) + forall (unbond in validators[validator_address].total_unbonds[epoch] s.t. unbond.start <= slash.epoch) total_unbonded += unbond.amount var last_slash = 0 forall (offset in 1..unbonding_length) do - forall (unbond in validators[validator_address].total_unbonded[epoch] s.t. unbond.start <= slash.epoch) + forall (unbond in validators[validator_address].total_unbonds[epoch] s.t. unbond.start <= slash.epoch) total_unbonded += unbond.amount var this_slash = (total_staked - total_unbonded) * slash.rate var diff_slashed_amount = last_slash - this_slash