From d53c2628abeed5d9faa5a0e4450f78e88d1bb044 Mon Sep 17 00:00:00 2001 From: Zane Date: Tue, 12 Nov 2024 20:11:41 +0100 Subject: [PATCH 01/11] change readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db9732a..0fe9f95 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,10 @@ If you want to test your project locally, you can use the following commands: ```bash # Starts the replica, running in the background +dfx extension install nns +dfx stop dfx start --background - +dfx extension run nns install # Deploys your canisters to the replica and generates your candid interface dfx deploy ``` From 6792616db28f2408690ed0c79581a269b571bf64 Mon Sep 17 00:00:00 2001 From: Zane Date: Wed, 13 Nov 2024 19:50:59 +0100 Subject: [PATCH 02/11] Updated NNS and SNS bindings also removed some dead/duplicated code --- .../External_Canisters/NNS/NNSMappings.mo | 62 +++-- .../External_Canisters/NNS/NNSTypes.mo | 216 ++++++++++++++---- .../External_Canisters/SNS/SNSTypes.mo | 24 +- .../Governance/FakeGovernanceService.mo | 13 +- .../Governance/GovernanceMappings.mo | 20 -- .../Governance/GovernanceService.mo | 35 +-- .../Governance/GovernanceUtils.mo | 122 ---------- .../Proposal/ProposalMappings.mo | 2 +- .../Proposal/ProposalService.mo | 46 +--- .../Tally/TallyService.mo | 52 +++-- .../Tracker/TrackerService.mo | 46 ++-- src/proposal_tracker_backend/main.mo | 36 +-- 12 files changed, 340 insertions(+), 334 deletions(-) delete mode 100644 src/proposal_tracker_backend/Governance/GovernanceMappings.mo delete mode 100644 src/proposal_tracker_backend/Governance/GovernanceUtils.mo diff --git a/src/proposal_tracker_backend/External_Canisters/NNS/NNSMappings.mo b/src/proposal_tracker_backend/External_Canisters/NNS/NNSMappings.mo index decadb5..8ada81f 100644 --- a/src/proposal_tracker_backend/External_Canisters/NNS/NNSMappings.mo +++ b/src/proposal_tracker_backend/External_Canisters/NNS/NNSMappings.mo @@ -1,4 +1,5 @@ import Result "mo:base/Result"; +import Nat64 "mo:base/Nat64"; module { public let NNSFunctions : [(Int32, Text, ?Text)] = [ @@ -55,27 +56,46 @@ module { (51, "DeployHostosToSomeNodes", null) ]; - public type NNSTopic = { - #Unspecified; - #ManageNeuron; - #ExchangeRate; - #NetworkEconomics; - #Governance; - #NodeAdmin; - #ParticipantManagement; - #SubnetManagement; - #NetworkCanisterManagement; - #Kyc; - #NodeProviderRewards; - // @deprecated - #SnsDecentralizationSale; - #SubnetReplicaVersionManagement; - #ReplicaVersionManagement; - #SnsAndCommunityFund; - #ApiBoundaryNodeManagement; - #SubnetRental; - }; - +// public type NNSTopic = { +// #Unspecified; +// #ManageNeuron; +// #ExchangeRate; +// #NetworkEconomics; +// #Governance; +// #NodeAdmin; +// #ParticipantManagement; +// #SubnetManagement; +// #NetworkCanisterManagement; +// #Kyc; +// #NodeProviderRewards; +// // @deprecated +// #SnsDecentralizationSale; +// #SubnetReplicaVersionManagement; +// #ReplicaVersionManagement; +// #SnsAndCommunityFund; +// #ApiBoundaryNodeManagement; +// #SubnetRental; +// }; + + public let NNSTopics : [{id : Nat64; name : Text;description : ?Text;}] = [ + {id : Nat64 = 0; description = ?"Unspecified"; name = "Unspecified"}, + {id : Nat64 = 1; description = ?"Neuron Management"; name = "ManageNeuron"}, + {id : Nat64 = 2; description = ?"Exchange Rate"; name = "ExchangeRate"}, + {id : Nat64 = 3; description = ?"Network Economics"; name = "NetworkEconomics"}, + {id : Nat64 = 4; description = ?"Governance"; name = "Governance"}, + {id : Nat64 = 5; description = ?"Node Admin"; name = "NodeAdmin"}, + {id : Nat64 = 6; description = ?"Participant Management"; name = "ParticipantManagement"}, + {id : Nat64 = 7; description = ?"Subnet Management"; name = "SubnetManagement"}, + {id : Nat64 = 8; description = ?"System Canister Management"; name = "NetworkCanisterManagement"}, + {id : Nat64 = 9; description = ?"KYC"; name = "Kyc"}, + {id : Nat64 = 10; description = ?"Node Provider Rewards"; name = "NodeProviderRewards"}, + {id : Nat64 = 11; description = ?"SNS Decentralization Swap"; name = "SnsDecentralizationSale"}, + {id : Nat64 = 12; description = ?"IC OS Version Election"; name = "ReplicaVersionManagement"}, + {id : Nat64 = 13; description = ?"IC OS Version Deployment"; name = "SubnetReplicaVersionManagement"}, + {id : Nat64 = 14; description = ?"SNS & Neurons' Fund"; name = "SnsAndCommunityFund"}, + {id : Nat64 = 15; description = ?"API Boundary Node Management"; name = "ApiBoundaryNodeManagement"}, + {id : Nat64 = 16; description = ?"Subnet Rental"; name = "SubnetRental"} + ]; public type NNSVote = { #Unspecified; //0 #Yes; //1 diff --git a/src/proposal_tracker_backend/External_Canisters/NNS/NNSTypes.mo b/src/proposal_tracker_backend/External_Canisters/NNS/NNSTypes.mo index ec5e677..c1bdbc5 100644 --- a/src/proposal_tracker_backend/External_Canisters/NNS/NNSTypes.mo +++ b/src/proposal_tracker_backend/External_Canisters/NNS/NNSTypes.mo @@ -6,6 +6,9 @@ module { public type Action = { #RegisterKnownNeuron : KnownNeuron; #ManageNeuron : ManageNeuron; + #UpdateCanisterSettings : UpdateCanisterSettings; + #InstallCode : InstallCode; + #StopOrStartCanister : StopOrStartCanister; #CreateServiceNervousSystem : CreateServiceNervousSystem; #ExecuteNnsFunction : ExecuteNnsFunction; #RewardNodeProvider : RewardNodeProvider; @@ -14,7 +17,7 @@ module { #SetDefaultFollowees : SetDefaultFollowees; #RewardNodeProviders : RewardNodeProviders; #ManageNetworkEconomics : NetworkEconomics; - #ApproveGenesisKyc : ApproveGenesisKyc; + #ApproveGenesisKyc : Principals; #AddOrRemoveNodeProvider : AddOrRemoveNodeProvider; #Motion : Motion; }; @@ -23,13 +26,21 @@ module { public type Amount = { e8s : Nat64 }; public type ApproveGenesisKyc = { principals : [Principal] }; public type Ballot = { vote : Int32; voting_power : Nat64 }; - public type BallotInfo = { vote : Int32; proposal_id : ?NeuronId }; + public type BallotInfo = { vote : Int32; proposal_id : ?ProposalId }; public type By = { #NeuronIdOrSubaccount : {}; #MemoAndController : ClaimOrRefreshNeuronFromAccount; #Memo : Nat64; }; public type Canister = { id : ?Principal }; + public type CanisterSettings = { + freezing_threshold : ?Nat64; + controllers : ?Controllers; + log_visibility : ?Int32; + wasm_memory_limit : ?Nat64; + memory_allocation : ?Nat64; + compute_allocation : ?Nat64; + }; public type CanisterStatusResultV2 = { status : ?Int32; freezing_threshold : ?Nat64; @@ -43,15 +54,6 @@ module { status : ?CanisterStatusResultV2; canister_id : ?Principal; }; - public type CfNeuron = { - has_created_neuron_recipes : ?Bool; - nns_neuron_id : Nat64; - amount_icp_e8s : Nat64; - }; - public type CfParticipant = { - hotkey_principal : Text; - cf_neurons : [CfNeuron]; - }; public type Change = { #ToRemove : NodeProvider; #ToAdd : NodeProvider }; public type ChangeAutoStakeMaturity = { requested_setting_for_auto_stake_maturity : Bool; @@ -114,6 +116,7 @@ module { sns_governance_canister_id : ?Principal; }; public type Configure = { operation : ?Operation }; + public type Controllers = { controllers : [Principal] }; public type Countries = { iso_codes : [Text] }; public type CreateServiceNervousSystem = { url : ?Text; @@ -127,6 +130,11 @@ module { swap_parameters : ?SwapParameters; initial_token_distribution : ?InitialTokenDistribution; }; + public type DateRangeFilter = { + start_timestamp_seconds : ?Nat64; + end_timestamp_seconds : ?Nat64; + }; + public type Decimal = { human_readable : ?Text }; public type DerivedProposalInformation = { swap_background_information : ?SwapBackgroundInformation; }; @@ -152,13 +160,15 @@ module { public type Followees = { followees : [NeuronId] }; public type Followers = { followers : [NeuronId] }; public type FollowersMap = { followers_map : [(Nat64, Followers)] }; - public type GetNeuronsFundAuditInfoRequest = { nns_proposal_id : ?NeuronId }; + public type GetNeuronsFundAuditInfoRequest = { + nns_proposal_id : ?ProposalId; + }; public type GetNeuronsFundAuditInfoResponse = { result : ?Result_6 }; public type GlobalTimeOfDay = { seconds_after_utc_midnight : ?Nat64 }; public type Governance = { default_followees : [(Int32, Followees)]; making_sns_proposal : ?MakingSnsProposal; - most_recent_monthly_node_provider_rewards : ?MostRecentMonthlyNodeProviderRewards; + most_recent_monthly_node_provider_rewards : ?MonthlyNodeProviderRewards; maturity_modulation_last_updated_at_timestamp_seconds : ?Nat64; wait_for_quiet_threshold_seconds : Nat64; metrics : ?GovernanceCachedMetrics; @@ -166,6 +176,7 @@ module { node_providers : [NodeProvider]; cached_daily_maturity_modulation_basis_points : ?Int32; economics : ?NetworkEconomics; + restore_aging_summary : ?RestoreAgingSummary; spawning_neurons : ?Bool; latest_reward_event : ?RewardEvent; to_claim_transfers : [NeuronStakeTransfer]; @@ -173,6 +184,7 @@ module { topic_followee_index : [(Int32, FollowersMap)]; migrations : ?Migrations; proposals : [(Nat64, ProposalData)]; + xdr_conversion_rate : ?XdrConversionRate; in_flight_commands : [(Nat64, NeuronInFlightCommand)]; neurons : [(Nat64, Neuron)]; genesis_timestamp_seconds : Nat64; @@ -198,11 +210,13 @@ module { not_dissolving_neurons_count : Nat64; total_locked_e8s : Nat64; neurons_fund_total_active_neurons : Nat64; + total_voting_power_non_self_authenticating_controller : ?Nat64; total_staked_maturity_e8s_equivalent : Nat64; not_dissolving_neurons_e8s_buckets_ect : [(Nat64, Float)]; total_staked_e8s_ect : Nat64; not_dissolving_neurons_staked_maturity_e8s_equivalent_sum : Nat64; dissolved_neurons_e8s : Nat64; + total_staked_e8s_non_self_authenticating_controller : ?Nat64; dissolving_neurons_e8s_buckets_seed : [(Nat64, Float)]; neurons_with_less_than_6_months_dissolve_delay_e8s : Nat64; not_dissolving_neurons_staked_maturity_e8s_equivalent_buckets : [ @@ -210,11 +224,13 @@ module { ]; dissolving_neurons_count_buckets : [(Nat64, Nat64)]; dissolving_neurons_e8s_buckets_ect : [(Nat64, Float)]; + non_self_authenticating_controller_neuron_subset_metrics : ?NeuronSubsetMetrics; dissolving_neurons_count : Nat64; dissolving_neurons_e8s_buckets : [(Nat64, Float)]; total_staked_maturity_e8s_equivalent_seed : Nat64; community_fund_total_staked_e8s : Nat64; not_dissolving_neurons_e8s_buckets_seed : [(Nat64, Float)]; + public_neuron_subset_metrics : ?NeuronSubsetMetrics; timestamp_seconds : Nat64; seed_neuron_count : Nat64; }; @@ -243,6 +259,20 @@ module { developer_distribution : ?DeveloperDistribution; swap_distribution : ?SwapDistribution; }; + public type InstallCode = { + skip_stopping_before_installing : ?Bool; + wasm_module_hash : ?Blob; + canister_id : ?Principal; + arg_hash : ?Blob; + install_mode : ?Int32; + }; + public type InstallCodeRequest = { + arg : ?Blob; + wasm_module : ?Blob; + skip_stopping_before_installing : ?Bool; + canister_id : ?Principal; + install_mode : ?Int32; + }; public type KnownNeuron = { id : ?NeuronId; known_neuron_data : ?KnownNeuronData; @@ -256,27 +286,41 @@ module { }; public type ListKnownNeuronsResponse = { known_neurons : [KnownNeuron] }; public type ListNeurons = { + include_public_neurons_in_full_neurons : ?Bool; neuron_ids : [Nat64]; + include_empty_neurons_readable_by_caller : ?Bool; include_neurons_readable_by_caller : Bool; }; public type ListNeuronsResponse = { neuron_infos : [(Nat64, NeuronInfo)]; full_neurons : [Neuron]; }; + public type ListNodeProviderRewardsRequest = { + date_filter : ?DateRangeFilter; + }; + public type ListNodeProviderRewardsResponse = { + rewards : [MonthlyNodeProviderRewards]; + }; public type ListNodeProvidersResponse = { node_providers : [NodeProvider] }; public type ListProposalInfo = { include_reward_status : [Int32]; omit_large_fields : ?Bool; - before_proposal : ?NeuronId; + before_proposal : ?ProposalId; limit : Nat32; exclude_topic : [Int32]; include_all_manage_neuron_proposals : ?Bool; include_status : [Int32]; }; public type ListProposalInfoResponse = { proposal_info : [ProposalInfo] }; + public type MakeProposalRequest = { + url : Text; + title : ?Text; + action : ?ProposalActionRequest; + summary : Text; + }; public type MakeProposalResponse = { message : ?Text; - proposal_id : ?NeuronId; + proposal_id : ?ProposalId; }; public type MakingSnsProposal = { proposal : ?Proposal; @@ -288,6 +332,25 @@ module { command : ?Command; neuron_id_or_subaccount : ?NeuronIdOrSubaccount; }; + public type ManageNeuronCommandRequest = { + #Spawn : Spawn; + #Split : Split; + #Follow : Follow; + #ClaimOrRefresh : ClaimOrRefresh; + #Configure : Configure; + #RegisterVote : RegisterVote; + #Merge : Merge; + #DisburseToNeuron : DisburseToNeuron; + #MakeProposal : MakeProposalRequest; + #StakeMaturity : StakeMaturity; + #MergeMaturity : MergeMaturity; + #Disburse : Disburse; + }; + public type ManageNeuronRequest = { + id : ?NeuronId; + command : ?ManageNeuronCommandRequest; + neuron_id_or_subaccount : ?NeuronIdOrSubaccount; + }; public type ManageNeuronResponse = { command : ?Command_1 }; public type Merge = { source_neuron_id : ?NeuronId }; public type MergeMaturity = { percentage_to_merge : Nat32 }; @@ -310,9 +373,14 @@ module { neuron_indexes_migration : ?Migration; copy_inactive_neurons_to_stable_memory_migration : ?Migration; }; - public type MostRecentMonthlyNodeProviderRewards = { + public type MonthlyNodeProviderRewards = { + minimum_xdr_permyriad_per_icp : ?Nat64; + registry_version : ?Nat64; + node_providers : [NodeProvider]; timestamp : Nat64; rewards : [RewardNodeProvider]; + xdr_conversion_rate : ?XdrConversionRate; + maximum_node_provider_rewards_e8s : ?Nat64; }; public type Motion = { motion_text : Text }; public type NetworkEconomics = { @@ -324,12 +392,14 @@ module { neuron_spawn_dissolve_delay_seconds : Nat64; minimum_icp_xdr_rate : Nat64; maximum_node_provider_rewards_e8s : Nat64; + neurons_fund_economics : ?NeuronsFundEconomics; }; public type Neuron = { id : ?NeuronId; staked_maturity_e8s_equivalent : ?Nat64; controller : ?Principal; recent_ballots : [BallotInfo]; + voting_power_refreshed_timestamp_seconds : ?Nat64; kyc_verified : Bool; neuron_type : ?Int32; not_for_profit : Bool; @@ -344,6 +414,7 @@ module { dissolve_state : ?DissolveState; followees : [(Int32, Followees)]; neuron_fees_e8s : Nat64; + visibility : ?Int32; transfer : ?NeuronStakeTransfer; known_neuron_data : ?KnownNeuronData; spawn_at_timestamp_seconds : ?Nat64; @@ -375,12 +446,14 @@ module { public type NeuronInfo = { dissolve_delay_seconds : Nat64; recent_ballots : [BallotInfo]; + voting_power_refreshed_timestamp_seconds : ?Nat64; neuron_type : ?Int32; created_timestamp_seconds : Nat64; state : Int32; stake_e8s : Nat64; joined_community_fund_timestamp_seconds : ?Nat64; retrieved_at_timestamp_seconds : Nat64; + visibility : ?Int32; known_neuron_data : ?KnownNeuronData; voting_power : Nat64; age_seconds : Nat64; @@ -394,6 +467,18 @@ module { transfer_timestamp : Nat64; block_height : Nat64; }; + public type NeuronSubsetMetrics = { + total_maturity_e8s_equivalent : ?Nat64; + maturity_e8s_equivalent_buckets : [(Nat64, Nat64)]; + voting_power_buckets : [(Nat64, Nat64)]; + total_staked_e8s : ?Nat64; + count : ?Nat64; + total_staked_maturity_e8s_equivalent : ?Nat64; + staked_maturity_e8s_equivalent_buckets : [(Nat64, Nat64)]; + staked_e8s_buckets : [(Nat64, Nat64)]; + total_voting_power : ?Nat64; + count_buckets : [(Nat64, Nat64)]; + }; public type NeuronsFundAuditInfo = { final_neurons_fund_participation : ?NeuronsFundParticipation; initial_neurons_fund_participation : ?NeuronsFundParticipation; @@ -404,14 +489,27 @@ module { initial_neurons_fund_participation : ?NeuronsFundParticipation; neurons_fund_refunds : ?NeuronsFundSnapshot; }; + public type NeuronsFundEconomics = { + maximum_icp_xdr_rate : ?Percentage; + neurons_fund_matched_funding_curve_coefficients : ?NeuronsFundMatchedFundingCurveCoefficients; + max_theoretical_neurons_fund_participation_amount_xdr : ?Decimal; + minimum_icp_xdr_rate : ?Percentage; + }; + public type NeuronsFundMatchedFundingCurveCoefficients = { + contribution_threshold_xdr : ?Decimal; + one_third_participation_milestone_xdr : ?Decimal; + full_participation_milestone_xdr : ?Decimal; + }; public type NeuronsFundNeuron = { - hotkey_principal : ?Text; + controller : ?Principal; + hotkeys : ?Principals; is_capped : ?Bool; nns_neuron_id : ?Nat64; amount_icp_e8s : ?Nat64; }; public type NeuronsFundNeuronPortion = { - hotkey_principal : ?Principal; + controller : ?Principal; + hotkeys : [Principal]; is_capped : ?Bool; maturity_equivalent_icp_e8s : ?Nat64; nns_neuron_id : ?NeuronId; @@ -448,6 +546,7 @@ module { #StopDissolving : {}; #StartDissolving : {}; #IncreaseDissolveDelay : IncreaseDissolveDelay; + #SetVisibility : SetVisibility; #JoinCommunityFund : {}; #LeaveCommunityFund : {}; #SetDissolveTimestamp : SetDissolveTimestamp; @@ -466,6 +565,7 @@ module { max_direct_participation_icp_e8s : ?Nat64; }; public type Percentage = { basis_points : ?Nat64 }; + public type Principals = { principals : [Principal] }; public type Progress = { #LastNeuronId : NeuronId }; public type Proposal = { url : Text; @@ -473,10 +573,24 @@ module { action : ?Action; summary : Text; }; + public type ProposalActionRequest = { + #RegisterKnownNeuron : KnownNeuron; + #ManageNeuron : ManageNeuronRequest; + #UpdateCanisterSettings : UpdateCanisterSettings; + #InstallCode : InstallCodeRequest; + #StopOrStartCanister : StopOrStartCanister; + #CreateServiceNervousSystem : CreateServiceNervousSystem; + #ExecuteNnsFunction : ExecuteNnsFunction; + #RewardNodeProvider : RewardNodeProvider; + #RewardNodeProviders : RewardNodeProviders; + #ManageNetworkEconomics : NetworkEconomics; + #ApproveGenesisKyc : Principals; + #AddOrRemoveNodeProvider : AddOrRemoveNodeProvider; + #Motion : Motion; + }; public type ProposalData = { - id : ?NeuronId; + id : ?ProposalId; failure_reason : ?GovernanceError; - cf_participants : [CfParticipant]; ballots : [(Nat64, Ballot)]; proposal_timestamp_seconds : Nat64; reward_event_round : Nat64; @@ -485,6 +599,7 @@ module { reject_cost_e8s : Nat64; derived_proposal_information : ?DerivedProposalInformation; latest_tally : ?Tally; + total_potential_voting_power : ?Nat64; sns_token_swap_lifecycle : ?Int32; decided_timestamp_seconds : Nat64; proposal : ?Proposal; @@ -493,8 +608,9 @@ module { executed_timestamp_seconds : Nat64; original_total_community_fund_maturity_e8s_equivalent : ?Nat64; }; + public type ProposalId = { id : Nat64 }; public type ProposalInfo = { - id : ?NeuronId; + id : ?ProposalId; status : Int32; topic : Int32; failure_reason : ?GovernanceError; @@ -506,14 +622,25 @@ module { reject_cost_e8s : Nat64; derived_proposal_information : ?DerivedProposalInformation; latest_tally : ?Tally; + total_potential_voting_power : ?Nat64; reward_status : Int32; decided_timestamp_seconds : Nat64; proposal : ?Proposal; proposer : ?NeuronId; executed_timestamp_seconds : Nat64; }; - public type RegisterVote = { vote : Int32; proposal : ?NeuronId }; + public type RegisterVote = { vote : Int32; proposal : ?ProposalId }; public type RemoveHotKey = { hot_key_to_remove : ?Principal }; + public type RestoreAgingNeuronGroup = { + count : ?Nat64; + previous_total_stake_e8s : ?Nat64; + current_total_stake_e8s : ?Nat64; + group_type : Int32; + }; + public type RestoreAgingSummary = { + groups : [RestoreAgingNeuronGroup]; + timestamp_seconds : ?Nat64; + }; public type Result = { #Ok; #Err : GovernanceError }; public type Result_1 = { #Error : GovernanceError; #NeuronId : NeuronId }; public type Result_10 = { #Ok : Ok_1; #Err : GovernanceError }; @@ -522,7 +649,10 @@ module { #Ok : GovernanceCachedMetrics; #Err : GovernanceError; }; - public type Result_4 = { #Ok : RewardNodeProviders; #Err : GovernanceError }; + public type Result_4 = { + #Ok : MonthlyNodeProviderRewards; + #Err : GovernanceError; + }; public type Result_5 = { #Ok : NeuronInfo; #Err : GovernanceError }; public type Result_6 = { #Ok : Ok; #Err : GovernanceError }; public type Result_7 = { #Ok : NodeProvider; #Err : GovernanceError }; @@ -535,7 +665,7 @@ module { total_available_e8s_equivalent : Nat64; latest_round_available_e8s_equivalent : ?Nat64; distributed_e8s_equivalent : Nat64; - settled_proposals : [NeuronId]; + settled_proposals : [ProposalId]; }; public type RewardMode = { #RewardToNeuron : RewardToNeuron; @@ -561,6 +691,7 @@ module { request : ?SetOpenTimeWindowRequest; swap_canister_id : ?Principal; }; + public type SetVisibility = { visibility : ?Int32 }; public type SettleCommunityFundParticipation = { result : ?Result_8; open_sns_token_swap_proposal_id : ?Nat64; @@ -582,6 +713,10 @@ module { maturity_e8s : Nat64; staked_maturity_e8s : Nat64; }; + public type StopOrStartCanister = { + action : ?Int32; + canister_id : ?Principal; + }; public type SwapBackgroundInformation = { ledger_index_canister_summary : ?CanisterSummary; fallback_controller_principal_ids : [Principal]; @@ -626,6 +761,10 @@ module { end_timestamp_seconds : Nat64; }; public type Tokens = { e8s : ?Nat64 }; + public type UpdateCanisterSettings = { + canister_id : ?Principal; + settings : ?CanisterSettings; + }; public type UpdateNodeProvider = { reward_account : ?AccountIdentifier }; public type VotingRewardParameters = { reward_rate_transition_duration : ?Duration; @@ -635,20 +774,11 @@ module { public type WaitForQuietState = { current_deadline_timestamp_seconds : Nat64; }; - - public type NervousSystemFunction = { - id : Nat64; - name : Text; - description : ?Text; - //function_type : opt FunctionType; + public type XdrConversionRate = { + xdr_permyriad_per_icp : ?Nat64; + timestamp_seconds : ?Nat64; }; - - public type ListNervousSystemFunctionsResponse = { - reserved_ids : [Nat64]; - functions : [NervousSystemFunction]; - }; - public type GovernanceCanister = actor { - //NNS + public type NNSCanister = actor { claim_gtc_neurons : shared (Principal, [NeuronId]) -> async Result; claim_or_refresh_neuron_from_account : shared ClaimOrRefreshNeuronFromAccount -> async ClaimOrRefreshNeuronFromAccountResponse; get_build_metadata : shared query () -> async Text; @@ -657,7 +787,7 @@ module { get_latest_reward_event : shared query () -> async RewardEvent; get_metrics : shared query () -> async Result_3; get_monthly_node_provider_rewards : shared () -> async Result_4; - get_most_recent_monthly_node_provider_rewards : shared query () -> async ?MostRecentMonthlyNodeProviderRewards; + get_most_recent_monthly_node_provider_rewards : shared query () -> async ?MonthlyNodeProviderRewards; get_network_economics_parameters : shared query () -> async NetworkEconomics; get_neuron_ids : shared query () -> async [Nat64]; get_neuron_info : shared query Nat64 -> async Result_5; @@ -666,19 +796,17 @@ module { get_node_provider_by_caller : shared query Null -> async Result_7; get_pending_proposals : shared query () -> async [ProposalInfo]; get_proposal_info : shared query Nat64 -> async ?ProposalInfo; + get_restore_aging_summary : shared query () -> async RestoreAgingSummary; list_known_neurons : shared query () -> async ListKnownNeuronsResponse; list_neurons : shared query ListNeurons -> async ListNeuronsResponse; + list_node_provider_rewards : shared query ListNodeProviderRewardsRequest -> async ListNodeProviderRewardsResponse; list_node_providers : shared query () -> async ListNodeProvidersResponse; list_proposals : shared query ListProposalInfo -> async ListProposalInfoResponse; - manage_neuron : shared ManageNeuron -> async ManageNeuronResponse; + manage_neuron : shared ManageNeuronRequest -> async ManageNeuronResponse; settle_community_fund_participation : shared SettleCommunityFundParticipation -> async Result; settle_neurons_fund_participation : shared SettleNeuronsFundParticipationRequest -> async SettleNeuronsFundParticipationResponse; - simulate_manage_neuron : shared ManageNeuron -> async ManageNeuronResponse; + simulate_manage_neuron : shared ManageNeuronRequest -> async ManageNeuronResponse; transfer_gtc_neuron : shared (NeuronId, NeuronId) -> async Result; update_node_provider : shared UpdateNodeProvider -> async Result; - - //SNS - get_metadata: shared query () -> async ( {url: ?Text; logo:?Text; name:?Text; description:?Text}); - list_nervous_system_functions : shared query () -> async(ListNervousSystemFunctionsResponse); } } \ No newline at end of file diff --git a/src/proposal_tracker_backend/External_Canisters/SNS/SNSTypes.mo b/src/proposal_tracker_backend/External_Canisters/SNS/SNSTypes.mo index cff6aa8..dc6579a 100644 --- a/src/proposal_tracker_backend/External_Canisters/SNS/SNSTypes.mo +++ b/src/proposal_tracker_backend/External_Canisters/SNS/SNSTypes.mo @@ -49,9 +49,7 @@ module { }; public type ClaimOrRefresh = { by : ?By }; public type ClaimOrRefreshResponse = { refreshed_neuron_id : ?NeuronId }; - public type ClaimSwapNeuronsRequest = { - neuron_parameters : [NeuronParameters]; - }; + public type ClaimSwapNeuronsRequest = { neuron_recipes : ?NeuronRecipes }; public type ClaimSwapNeuronsResponse = { claim_swap_neurons_result : ?ClaimSwapNeuronsResult; }; @@ -110,6 +108,7 @@ module { public type DefiniteCanisterSettingsArgs = { freezing_threshold : Nat; controllers : [Principal]; + wasm_memory_limit : ?Nat; memory_allocation : Nat; compute_allocation : Nat; }; @@ -327,6 +326,7 @@ module { neuron_fees_e8s : Nat64; }; public type NeuronId = { id : Blob }; + public type NeuronIds = { neuron_ids : [NeuronId] }; public type NeuronInFlightCommand = { command : ?Command_2; timestamp : Nat64; @@ -345,6 +345,20 @@ module { permission_type : [Int32]; }; public type NeuronPermissionList = { permissions : [Int32] }; + public type NeuronRecipe = { + controller : ?Principal; + dissolve_delay_seconds : ?Nat64; + participant : ?Participant; + stake_e8s : ?Nat64; + followees : ?NeuronIds; + neuron_id : ?NeuronId; + }; + public type NeuronRecipes = { neuron_recipes : [NeuronRecipe] }; + public type NeuronsFund = { + nns_neuron_hotkeys : ?Principals; + nns_neuron_controller : ?Principal; + nns_neuron_id : ?Nat64; + }; public type Operation = { #ChangeAutoStakeMaturity : ChangeAutoStakeMaturity; #StopDissolving : {}; @@ -352,7 +366,9 @@ module { #IncreaseDissolveDelay : IncreaseDissolveDelay; #SetDissolveTimestamp : SetDissolveTimestamp; }; + public type Participant = { #NeuronsFund : NeuronsFund; #Direct : {} }; public type Percentage = { basis_points : ?Nat64 }; + public type Principals = { principals : [Principal] }; public type Proposal = { url : Text; title : Text; @@ -466,7 +482,7 @@ module { public type WaitForQuietState = { current_deadline_timestamp_seconds : Nat64; }; - public type Self = Governance -> async actor { + public type SNSCanister = actor { claim_swap_neurons : shared ClaimSwapNeuronsRequest -> async ClaimSwapNeuronsResponse; fail_stuck_upgrade_in_progress : shared {} -> async {}; get_build_metadata : shared query () -> async Text; diff --git a/src/proposal_tracker_backend/Governance/FakeGovernanceService.mo b/src/proposal_tracker_backend/Governance/FakeGovernanceService.mo index fff0339..50b761d 100644 --- a/src/proposal_tracker_backend/Governance/FakeGovernanceService.mo +++ b/src/proposal_tracker_backend/Governance/FakeGovernanceService.mo @@ -23,6 +23,8 @@ module{ known_neuron_data : ?NNSTypes.KnownNeuronData; voting_power : Nat64; age_seconds : Nat64; + voting_power_refreshed_timestamp_seconds : ?Nat64; + visibility : ?Int32; }; type Proposal = { @@ -43,6 +45,7 @@ module{ proposal : ?NNSTypes.Proposal; proposer : ?NNSTypes.NeuronId; executed_timestamp_seconds : Nat64; + total_potential_voting_power : ?Nat64; }; public class FakeGovernanceService(logService : LogTypes.LogService) { @@ -122,11 +125,8 @@ module{ #ok({name = ?"fake governance"; description = ?"fake governance description"}); }; - public func getGovernanceFunctions(_ : Text) : async* Result.Result{ - #ok({ - reserved_ids = [1,2,3,4,5,6,7,8,9,10,11,12,13]; - functions = []; - }); + public func getGovernanceFunctions(_ : Text) : async* Result.Result<[{id : Nat64;name : Text;description : ?Text;}], Text>{ + #ok(NNSMappings.NNSTopics); }; public func addNeuronWithId(neuronId : Nat64) : Nat64 { @@ -158,6 +158,8 @@ module{ stake_e8s = 0; state = 0; voting_power = 0; + voting_power_refreshed_timestamp_seconds = null; + visibility = ?1; }; neurons := List.push((neuronId, neuron), neurons); @@ -203,6 +205,7 @@ module{ }; proposer = ?{id = lastProposalId}; executed_timestamp_seconds = 0; + total_potential_voting_power = null; }; diff --git a/src/proposal_tracker_backend/Governance/GovernanceMappings.mo b/src/proposal_tracker_backend/Governance/GovernanceMappings.mo deleted file mode 100644 index ab7bc3b..0000000 --- a/src/proposal_tracker_backend/Governance/GovernanceMappings.mo +++ /dev/null @@ -1,20 +0,0 @@ -import Result "mo:base/Result"; - -module { - - - public type Vote = { - #Unspecified; //0 - #Yes; //1 - #No; //2 - }; - - public func tryMapVote(vote: Int32): Result.Result { - switch(vote){ - case(0){#ok(#Unspecified)}; - case(1){#ok(#Yes)}; - case(2){#ok(#No)}; - case(_){#err("Unknown vote value")}; - } - }; -} \ No newline at end of file diff --git a/src/proposal_tracker_backend/Governance/GovernanceService.mo b/src/proposal_tracker_backend/Governance/GovernanceService.mo index 2efe75f..96bd2c8 100644 --- a/src/proposal_tracker_backend/Governance/GovernanceService.mo +++ b/src/proposal_tracker_backend/Governance/GovernanceService.mo @@ -1,5 +1,4 @@ -import GT "./GovernanceTypes"; -import GU "./GovernanceUtils"; + import Result "mo:base/Result"; import Buffer "mo:base/Buffer"; import Array "mo:base/Array"; @@ -10,14 +9,17 @@ import Option "mo:base/Option"; import Nat64 "mo:base/Nat64"; import Error "mo:base/Error"; import Utils "../utils"; +import NNSTypes "../External_Canisters/NNS/NNSTypes"; +import NNSMappings "../External_Canisters/NNS/NNSMappings"; +import SNSTypes "../External_Canisters/SNS/SNSTypes"; module { public class GovernanceService() { // let BATCH_SIZE_LIMIT = 50; let NNS_GOVERNANCE_ID = "rrkah-fqaaa-aaaaa-aaaaq-cai"; - public func listProposals(governanceId : Text, info : GT.ListProposalInfo) : async* Result.Result{ - let gc : GT.GovernanceCanister = actor(governanceId); + public func listProposals(governanceId : Text, info : NNSTypes.ListProposalInfo) : async* Result.Result{ + let gc : NNSTypes.NNSCanister = actor(governanceId); try{ let res = await gc.list_proposals(info); #ok(res) @@ -27,8 +29,8 @@ module { }; //todo: change for sns - public func getPendingProposals(governanceId : Text) : async* Result.Result<[GT.ProposalInfo], Text>{ - let gc : GT.GovernanceCanister = actor(governanceId); + public func getPendingProposals(governanceId : Text) : async* Result.Result<[NNSTypes.ProposalInfo], Text>{ + let gc : NNSTypes.NNSCanister = actor(governanceId); try{ let res = await gc.get_pending_proposals(); #ok(res) @@ -39,31 +41,38 @@ module { public func getMetadata(governanceId : Text) : async* Result.Result<( {name:?Text; description:?Text}), Text>{ //verify canister exists and is a governance canister - let gc : GT.GovernanceCanister = actor(governanceId); if (governanceId == NNS_GOVERNANCE_ID){ return #ok({name = ?"NNS"; description = ?"Network Nervous System"}) }; + let gc : SNSTypes.SNSCanister = actor(governanceId); try { - let res = await gc.get_metadata(); + let res = await gc.get_metadata({}); #ok(res) } catch(e){ return #err(Error.message(e)) }; }; - public func getGovernanceFunctions(governanceId : Text) : async* Result.Result{ - let gc : GT.GovernanceCanister = actor(governanceId); + public func getGovernanceFunctions(governanceId : Text) : async* Result.Result<[{id : Nat64;name : Text;description : ?Text;}], Text>{ + if (governanceId == NNS_GOVERNANCE_ID){ + return #ok(NNSMappings.NNSTopics); + }; + let gc : SNSTypes.SNSCanister = actor(governanceId); try{ let res = await gc.list_nervous_system_functions(); - #ok(res) + let buf = Buffer.Buffer<{id : Nat64;name : Text;description : ?Text;}>(Array.size(res.functions)); + for(f in res.functions.vals()){ + buf.add({id = f.id; name = f.name; description = f.description}); + }; + #ok(Buffer.toArray(buf)) } catch(e){ return #err(Error.message(e)) } }; - public func listNeurons(governanceId : Text, args : GT.ListNeurons) : async* Result.Result{ - let gc : GT.GovernanceCanister = actor(governanceId); + public func listNeurons(governanceId : Text, args : NNSTypes.ListNeurons) : async* Result.Result{ + let gc : NNSTypes.NNSCanister = actor(governanceId); try{ let res = await gc.list_neurons(args); #ok(res) diff --git a/src/proposal_tracker_backend/Governance/GovernanceUtils.mo b/src/proposal_tracker_backend/Governance/GovernanceUtils.mo deleted file mode 100644 index a1d6099..0000000 --- a/src/proposal_tracker_backend/Governance/GovernanceUtils.mo +++ /dev/null @@ -1,122 +0,0 @@ -module{ - - public let NNSFunctions : [(Int32, Text, ?Text)] = [ - (0, "Unspecified", null), - (1, "CreateSubnet", null), - (2, "AddNodeToSubnet", null), - (3, "NnsCanisterInstall", null), - (4, "NnsCanisterUpgrade", null), - (5, "BlessReplicaVersion", null), - (6, "RecoverSubnet", null), - (7, "UpdateConfigOfSubnet", null), - (8, "AssignNoid", null), - (9, "NnsRootUpgrade", null), - (10, "IcpXdrConversionRate", null), - (11, "DeployGuestosToAllSubnetNodes", null), - (12, "ClearProvisionalWhitelist", null), - (13, "RemoveNodesFromSubnet", null), - (14, "SetAuthorizedSubnetworks", null), - (15, "SetFirewallConfig", null), - (16, "UpdateNodeOperatorConfig", null), - (17, "StopOrStartNnsCanister", null), - (18, "RemoveNodes", null), - (19, "UninstallCode", null), - (20, "UpdateNodeRewardsTable", null), - (21, "AddOrRemoveDataCenters", null), - (22, "UpdateUnassignedNodesConfig", null), - (23, "RemoveNodeOperators", null), - (24, "RerouteCanisterRanges", null), - (25, "AddFirewallRules", null), - (26, "RemoveFirewallRules", null), - (27, "UpdateFirewallRules", null), - (28, "PrepareCanisterMigration", null), - (29, "CompleteCanisterMigration", null), - (30, "AddSnsWasm", null), - (31, "ChangeSubnetMembership", null), - (32, "UpdateSubnetType", null), - (33, "ChangeSubnetTypeAssignment", null), - (34, "UpdateSnsWasmSnsSubnetIds", null), - (35, "UpdateAllowedPrincipals", null), - (36, "RetireReplicaVersion", null), - (37, "InsertSnsWasmUpgradePathEntries", null), - (38, "ReviseElectedGuestosVersions", null), - (39, "BitcoinSetConfig", null), - (40, "UpdateElectedHostosVersions", null), - (41, "UpdateNodesHostosVersion", null), - (42, "HardResetNnsRootToVersion", null), - (43, "AddApiBoundaryNodes", null), - (44, "RemoveApiBoundaryNodes", null), - (46, "UpdateApiBoundaryNodesVersion", null), - (47, "DeployGuestosToSomeApiBoundaryNodes", null), - (48, "DeployGuestosToAllUnassignedNodes", null), - (49, "UpdateSshReadonlyAccessForAllUnassignedNodes", null), - (50, "ReviseElectedHostosVersions", null), - (51, "DeployHostosToSomeNodes", null) - ]; - - public type NNSTopic = { - #Unspecified; - #ManageNeuron; - #ExchangeRate; - #NetworkEconomics; - #Governance; - #NodeAdmin; - #ParticipantManagement; - #SubnetManagement; - #NetworkCanisterManagement; - #Kyc; - #NodeProviderRewards; - // @deprecated - #SnsDecentralizationSale; - #SubnetReplicaVersionManagement; - #ReplicaVersionManagement; - #SnsAndCommunityFund; - #ApiBoundaryNodeManagement; - #SubnetRental; - }; - - public type NNSVote = { - #Unspecified; //0 - #Yes; //1 - #No; //2 - }; - - public type ProposalRewardStatus = { - #Unknown; //0 - - // The proposal still accept votes, for the purpose of - // vote rewards. This implies nothing on the ProposalStatus. - #AcceptVotes; //1 - - // The proposal no longer accepts votes. It is due to settle - // at the next reward event. - #ReadyToSettle; //2 - - // The proposal has been taken into account in a reward event. - #Settled; //3 - - // The proposal is not eligible to be taken into account in a reward event. - #Ineligible; //4 - }; - - public type ProposalStatus = { - #Unknown; //0 - - // A decision (accept/reject) has yet to be made. - #Open; //1 - - // The proposal has been rejected. - #Rejected; - - // The proposal has been accepted. At this time, either execution - // as not yet started, or it has but the outcome is not yet known. - #Accepted; - - // The proposal was accepted and successfully executed. - #Executed; - - // The proposal was accepted, but execution failed. - #Failed; - } - -} diff --git a/src/proposal_tracker_backend/Proposal/ProposalMappings.mo b/src/proposal_tracker_backend/Proposal/ProposalMappings.mo index a4875e6..5b92a1b 100644 --- a/src/proposal_tracker_backend/Proposal/ProposalMappings.mo +++ b/src/proposal_tracker_backend/Proposal/ProposalMappings.mo @@ -6,7 +6,7 @@ import Buffer "mo:base/Buffer"; import Time "mo:base/Time"; import Int "mo:base/Int"; import Int64 "mo:base/Int64"; -import G "../Governance/GovernanceTypes"; +import G "../External_Canisters/NNS/NNSTypes"; import PT "./ProposalTypes"; diff --git a/src/proposal_tracker_backend/Proposal/ProposalService.mo b/src/proposal_tracker_backend/Proposal/ProposalService.mo index 802fc2d..65403bc 100644 --- a/src/proposal_tracker_backend/Proposal/ProposalService.mo +++ b/src/proposal_tracker_backend/Proposal/ProposalService.mo @@ -1,6 +1,5 @@ import GS "../Governance/GovernanceService"; -import GT "../Governance/GovernanceTypes"; -import GU "../Governance/GovernanceUtils"; +import GT "../External_Canisters/NNS/NNSTypes"; import LT "../Log/LogTypes"; import PT "./ProposalTypes"; import Result "mo:base/Result"; @@ -13,32 +12,13 @@ import Option "mo:base/Option"; import Utils "../utils"; // TODO: separate functions and topics // Reconciciliate NNS and SNS differences: (no active_proposals endpoint and topics instead of types) - // Status that reflects when proposal no longer accepts votes - module{ let BATCH_SIZE_LIMIT = 50; let NNS_GOVERNANCE_ID = "rrkah-fqaaa-aaaaa-aaaaq-cai"; + //todo fix this public class ProposalService(governanceService : GS.GovernanceService, logService : LT.LogService){ - public func getValidTopicIds(governanceId : Text) : async* Result.Result<[(Int32, Text, ?Text)], Text>{ - if (governanceId == NNS_GOVERNANCE_ID){ - return #ok(GU.NNSFunctions); - }; - let buf = Buffer.Buffer<(Int32, Text, ?Text)>(50); - let res = await* governanceService.getGovernanceFunctions(governanceId); - switch(res){ - case(#ok(res)){ - for(function in Array.vals(res.functions)){ - buf.add((Int32.fromInt64(Int64.fromNat64(function.id))), function.name, function.description); - }; - return #ok(Buffer.toArray(buf)); - }; - case(#err(err)){ - return #err(err); - }; - }; - }; public func listProposalsFromId(governanceId : Text, _from : ?PT.ProposalId, args : PT.ListProposalArgs) : async* Result.Result{ @@ -110,25 +90,13 @@ module{ #ok({proposal_info = Buffer.toArray(proposalBuffer)}); } }; - - // public func processIncludeTopics(validTopics : [(Int32, Text, ?Text)], topicsToInclude : [Int32]) : [Int32] { - // return Array.mapFilter<(Int32, Text, ?Text), Int32>(validTopics, func (t : (Int32, Text, ?Text)) : ?Int32 { - // for(id in Array.vals(topicsToInclude)){ - // if(id != t.0){ - // return ?t.0; - // } - // }; - // return null; - // }); - // }; - - public func processIncludeTopics(validTopics : [(Int32, Text, ?Text)], topicsToInclude : [Int32]) : [Int32] { + public func processIncludeTopics(validTopics : [{id : Nat64;name : Text;description : ?Text;}], topicsToInclude : [Nat64]) : [Nat64] { - let buf = Buffer.Buffer(50); + let buf = Buffer.Buffer(50); for(id in Array.vals(validTopics)){ - if(Option.isNull(Array.find(topicsToInclude, func (x : Int32) : Bool { return x == id.0 }))){ - buf.add(id.0); + if(Option.isNull(Array.find(topicsToInclude, func (x : Nat64) : Bool { return x == id.id }))){ + buf.add(id.id); }; }; @@ -136,7 +104,7 @@ module{ }; - public func ListProposalArgsDefault() : PT.ListProposalArgs { + public func listProposalArgsDefault() : PT.ListProposalArgs { { includeRewardStatus = []; omitLargeFields = ?true; diff --git a/src/proposal_tracker_backend/Tally/TallyService.mo b/src/proposal_tracker_backend/Tally/TallyService.mo index 4c32ed8..cfc9492 100644 --- a/src/proposal_tracker_backend/Tally/TallyService.mo +++ b/src/proposal_tracker_backend/Tally/TallyService.mo @@ -14,11 +14,11 @@ import PT "../Proposal/ProposalTypes"; import { nhash; thash; phash; n64hash; i32hash} "mo:map/Map"; import GS "../Governance/GovernanceService"; import LT "../Log/LogTypes"; -import GT "../Governance/GovernanceTypes"; +import GT "../External_Canisters/NNS/NNSTypes"; import TT "../Tracker/TrackerTypes"; import TallyTypes "../Tally/TallyTypes"; import Utils "../utils"; -import GM "../Governance/GovernanceMappings"; +import NNSMappings "../External_Canisters/NNS/NNSMappings"; module { @@ -102,7 +102,6 @@ module { }; }; - // Feed id based on hash calculated by neurons ids and topics to avoid duplication public class TallyService(tallyModel : TallyModel, logService: LT.LogService, governanceService : GS.GovernanceService, trackerService : TT.TrackerService) { var updateState : UpdateState = #Stopped; @@ -122,23 +121,6 @@ module { return #ok() }; - public func fetchProposalsAndUpdate() : async* (){ - if(updateState == #Running){ - logService.logWarn("Update already running", ?"[update]"); - return; - }; - - updateState:= #Running; - try{ - await* trackerService.update(func(governanceId : Text, new : [PT.ProposalAPI], updated : [PT.ProposalAPI]) : async* () { - await* update(governanceId, new, updated); - }); - } catch(e){ - updateState:= #Stopped; - }; - updateState:= #Stopped; - }; - public func cancelTimer() : async Result.Result<(), Text> { switch(tallyModel.timerId){ case(?t){ @@ -220,6 +202,26 @@ module { Map.get(tallyModel.talliesById, thash, tallyId); }; + + //TODO: change + public func fetchProposalsAndUpdate() : async* (){ + if(updateState == #Running){ + logService.logWarn("Update already running", ?"[update]"); + return; + }; + + updateState:= #Running; + try{ + await* trackerService.update(func(governanceId : Text, new : [PT.ProposalAPI], updated : [PT.ProposalAPI]) : async* () { + await* update(governanceId, new, updated); + }); + } catch(e){ + updateState:= #Stopped; + }; + updateState:= #Stopped; + }; + + public func update(governanceId : Text, newProposals : [PT.ProposalAPI], changedProposals : [PT.ProposalAPI]) : async* () { //init proposal map for governance id if it doesnt exist @@ -285,6 +287,8 @@ module { let res = await* governanceService.listNeurons(governanceId, { neuron_ids = chunk; include_neurons_readable_by_caller = false; + include_empty_neurons_readable_by_caller = null; + include_public_neurons_in_full_neurons = null; }); switch(res){ @@ -329,7 +333,7 @@ module { let #ok(proposal) = Result.fromOption(Map.get(proposals, n64hash, pId.id), "proposal not found") else { - //logService.logError("proposal not found", ?"[getProposalDeltaAndUpdateState]"); //TODO: reenable + logService.logError("proposal not found", ?"[getProposalDeltaAndUpdateState]"); continue l; }; @@ -341,7 +345,7 @@ module { // switch(Map.get(proposal.ballots, n64hash, neuronId)){ case(?vote) { - let newVote = GM.tryMapVote(ballot.vote); + let newVote = NNSMappings.tryMapVoteFromInt(ballot.vote); switch(newVote){ case(#ok(mappedBallotVote)) { if(vote != mapVote(mappedBallotVote, proposal.isSettled)){ @@ -356,7 +360,7 @@ module { }; }; case(_){ - let vote = GM.tryMapVote(ballot.vote); + let vote = NNSMappings.tryMapVoteFromInt(ballot.vote); switch(vote){ case(#ok(mappedBallotVote)){ let v = mapVote(mappedBallotVote, proposal.isSettled); @@ -548,7 +552,7 @@ module { await sub.tallyUpdate(tallies); }; - func mapVote(vote : GM.Vote, isSettled : Bool) : NeuronVote{ + func mapVote(vote : NNSMappings.NNSVote, isSettled : Bool) : NeuronVote{ switch(vote){ case(#Yes){ #Yes diff --git a/src/proposal_tracker_backend/Tracker/TrackerService.mo b/src/proposal_tracker_backend/Tracker/TrackerService.mo index fd6a174..d7b34eb 100644 --- a/src/proposal_tracker_backend/Tracker/TrackerService.mo +++ b/src/proposal_tracker_backend/Tracker/TrackerService.mo @@ -5,7 +5,7 @@ import Time "mo:base/Time"; import Array "mo:base/Array"; import Result "mo:base/Result"; import Timer "mo:base/Timer"; -import G "../Governance/GovernanceTypes"; +import G "../External_Canisters/NNS/NNSTypes"; import PT "../Proposal/ProposalTypes"; import PM "../Proposal/ProposalMappings"; import TT "./TrackerTypes"; @@ -128,7 +128,7 @@ module { let res = await* governanceService.getMetadata(governancePrincipal); switch(res){ case(#ok(metadata)){ - switch(await* proposalService.getValidTopicIds(governancePrincipal)){ + switch(await* governanceService.getGovernanceFunctions(governancePrincipal)){ case(#ok(validTopics)){ repository.addGovernance(governancePrincipal, metadata.name, metadata.description, filterValidTopics(validTopics, topicStrategy)); }; @@ -146,14 +146,6 @@ module { func performCleanupStrategy(governanceData : TT.GovernanceData) : () { switch(args.cleanupStrategy){ - case(#DeleteAfterExecution){ - for(p in LinkedList.vals(governanceData.proposals)){ - if(not Map.has(governanceData.activeProposalsSet, n64hash, p.id)){ - // proposal has executed, so it can be removed - ignore repository.deleteProposal(governanceData, p.id); - } - } - }; case(#DeleteAfterTime(timeframe)){ let currentTime = Time.now(); for(p in LinkedList.vals(governanceData.proposals)){ @@ -175,40 +167,48 @@ module { } } }; - case(#DeleteAfterVotingPeriodEnds){ - for(p in LinkedList.vals(governanceData.proposals)){ - if(p.rewardStatus == #Settled){ - ignore repository.deleteProposal(governanceData, p.id); - } - } - }; + // case(#DeleteAfterExecution){ + // for(p in LinkedList.vals(governanceData.proposals)){ + // if(not Map.has(governanceData.activeProposalsSet, n64hash, p.id)){ + // // proposal has executed, so it can be removed + // ignore repository.deleteProposal(governanceData, p.id); + // } + // } + // }; + // case(#DeleteAfterVotingPeriodEnds){ + // for(p in LinkedList.vals(governanceData.proposals)){ + // if(p.rewardStatus == #Settled){ + // ignore repository.deleteProposal(governanceData, p.id); + // } + // } + // }; } }; - func filterValidTopics(topics : [(Int32, Text, ?Text)], topicStrategy : TT.TopicStrategy) : TT.Topics { + func filterValidTopics(topics : [{id : Nat64; name : Text;description : ?Text;}], topicStrategy : TT.TopicStrategy) : TT.Topics { let topicMap : TT.Topics = Map.new(); switch(topicStrategy){ case(#All){ for(t in Array.vals(topics)){ - Map.set(topicMap, i32hash, t.0, {name = t.1; description = t.2}); + Map.set(topicMap, i32hash, Int32.fromNat32(Nat64.toNat32(t.id)), {name = t.name; description = t.description}); } }; case(#Include(ids)){ for(t in Array.vals(topics)){ if(Option.isSome(Array.find(ids, func (x : Int32) : Bool { - x == t.0 + x == Int32.fromNat32(Nat64.toNat32(t.id)) }))){ - Map.set(topicMap, i32hash, t.0, {name = t.1; description = t.2}); + Map.set(topicMap, i32hash, Int32.fromNat32(Nat64.toNat32(t.id)), {name = t.name; description = t.description}); }; }; }; case(#Exclude(ids)){ for(t in Array.vals(topics)){ if(Option.isNull(Array.find(ids, func (x : Int32) : Bool { - x == t.0 + x == Int32.fromNat32(Nat64.toNat32(t.id)) }))){ - Map.set(topicMap, i32hash, t.0, {name = t.1; description = t.2}); + Map.set(topicMap, i32hash, Int32.fromNat32(Nat64.toNat32(t.id)), {name = t.name; description = t.description}); }; }; }; diff --git a/src/proposal_tracker_backend/main.mo b/src/proposal_tracker_backend/main.mo index 2f16073..2943a77 100644 --- a/src/proposal_tracker_backend/main.mo +++ b/src/proposal_tracker_backend/main.mo @@ -7,7 +7,7 @@ import Time "mo:base/Time"; import Array "mo:base/Array"; import Result "mo:base/Result"; import Timer "mo:base/Timer"; -import G "./Governance/GovernanceTypes"; +import G "./External_Canisters/NNS/NNSTypes"; import GS "./Governance/GovernanceService"; import FakeGovernance "./Governance/FakeGovernanceService"; import PT "./Proposal/ProposalTypes"; @@ -38,7 +38,7 @@ actor class ProposalTrackerBackend() = { }); stable let tallyModel = TallyService.initTallyModel(); - let tallyService = TallyService.TallyService(tallyModel, logService, fakeGovernanceService, trackerService); + let tallyService = TallyService.TallyService(tallyModel, logService, governanceService, trackerService); system func postupgrade() { if(Option.isSome(tallyModel.timerId)){ @@ -124,6 +124,22 @@ actor class ProposalTrackerBackend() = { }); }; + public func testAddCodegovTally() : async Result.Result{ + let codegovNeurons : [TallyTypes.NeuronId] = [118900764328536345, 12979846186887799326, 2692859404205778191, 16405079610149095765, 16459595263909468577, 6542438359604605534, 14998600334911702241, 739503821726316206]; + + for(neuron in codegovNeurons.vals()){ + ignore fakeGovernanceService.addNeuronWithId(neuron); + }; + + await* tallyService.addTally({ + governanceId = "rrkah-fqaaa-aaaaa-aaaaq-cai"; + alias = ?"Codegov"; + topics = [1,2,3,4,5,6,7,8,9,10,11,12,13]; + neurons = codegovNeurons; + subscriber = Principal.fromText("7g2oq-raaaa-aaaap-qb7sq-cai"); + }); + }; + public func testVoteWithTallyOnProposal(tallyId : Text, proposalId : Nat64, vote : {#No; #Unspecified; #Yes}) : async Result.Result<(), Text>{ let t = tallyService.getTally(tallyId); switch(t){ @@ -151,22 +167,6 @@ actor class ProposalTrackerBackend() = { await* tallyService.fetchProposalsAndUpdate(); }; - public func testAddCodegovTally() : async Result.Result{ - let codegovNeurons : [TallyTypes.NeuronId] = [118900764328536345, 12979846186887799326, 2692859404205778191, 16405079610149095765, 16459595263909468577, 6542438359604605534, 14998600334911702241, 739503821726316206]; - - for(neuron in codegovNeurons.vals()){ - ignore fakeGovernanceService.addNeuronWithId(neuron); - }; - - await* tallyService.addTally({ - governanceId = "rrkah-fqaaa-aaaaa-aaaaq-cai"; - alias = ?"Codegov"; - topics = [1,2,3,4,5,6,7,8,9,10,11,12,13]; - neurons = codegovNeurons; - subscriber = Principal.fromText("7g2oq-raaaa-aaaap-qb7sq-cai"); - }); - }; - public func testAddPendingProposal(id : ?Nat64) : async Nat64{ switch(id){ case(?unwrapId){ From c7b651fafbbffa499c9f4445bde6673731a1287f Mon Sep 17 00:00:00 2001 From: Zane Date: Wed, 13 Nov 2024 19:51:11 +0100 Subject: [PATCH 03/11] updated dfx version to 0.24.1 --- dfx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dfx.json b/dfx.json index 9b130a6..769bc36 100644 --- a/dfx.json +++ b/dfx.json @@ -30,5 +30,5 @@ }, "output_env_file": ".env", "version": 1, - "dfx": "0.20.1" + "dfx": "0.24.1" } From ef072a683c9e1f7bb7de54c38df6f22a6b5a381a Mon Sep 17 00:00:00 2001 From: Zane Date: Wed, 13 Nov 2024 20:47:13 +0100 Subject: [PATCH 04/11] delete duplicate code --- .../Governance/GovernanceTypes.mo | 689 ------------------ 1 file changed, 689 deletions(-) delete mode 100644 src/proposal_tracker_backend/Governance/GovernanceTypes.mo diff --git a/src/proposal_tracker_backend/Governance/GovernanceTypes.mo b/src/proposal_tracker_backend/Governance/GovernanceTypes.mo deleted file mode 100644 index bf13a1c..0000000 --- a/src/proposal_tracker_backend/Governance/GovernanceTypes.mo +++ /dev/null @@ -1,689 +0,0 @@ -// This is a generated Motoko binding. -// Please use `import service "ic:canister_id"` instead to call canisters on the IC if possible. - -module { - public type AccountIdentifier = { hash : Blob }; - public type Action = { - #RegisterKnownNeuron : KnownNeuron; - #ManageNeuron : ManageNeuron; - #CreateServiceNervousSystem : CreateServiceNervousSystem; - #ExecuteNnsFunction : ExecuteNnsFunction; - #RewardNodeProvider : RewardNodeProvider; - #OpenSnsTokenSwap : OpenSnsTokenSwap; - #SetSnsTokenSwapOpenTimeWindow : SetSnsTokenSwapOpenTimeWindow; - #SetDefaultFollowees : SetDefaultFollowees; - #RewardNodeProviders : RewardNodeProviders; - #ManageNetworkEconomics : NetworkEconomics; - #ApproveGenesisKyc : ApproveGenesisKyc; - #AddOrRemoveNodeProvider : AddOrRemoveNodeProvider; - #Motion : Motion; - }; - public type AddHotKey = { new_hot_key : ?Principal }; - public type AddOrRemoveNodeProvider = { change : ?Change }; - public type Amount = { e8s : Nat64 }; - public type ApproveGenesisKyc = { principals : [Principal] }; - public type Ballot = { vote : Int32; voting_power : Nat64 }; - public type BallotInfo = { vote : Int32; proposal_id : ?NeuronId }; - public type By = { - #NeuronIdOrSubaccount : {}; - #MemoAndController : ClaimOrRefreshNeuronFromAccount; - #Memo : Nat64; - }; - public type Canister = { id : ?Principal }; - public type CanisterStatusResultV2 = { - status : ?Int32; - freezing_threshold : ?Nat64; - controllers : [Principal]; - memory_size : ?Nat64; - cycles : ?Nat64; - idle_cycles_burned_per_day : ?Nat64; - module_hash : Blob; - }; - public type CanisterSummary = { - status : ?CanisterStatusResultV2; - canister_id : ?Principal; - }; - public type CfNeuron = { - has_created_neuron_recipes : ?Bool; - nns_neuron_id : Nat64; - amount_icp_e8s : Nat64; - }; - public type CfParticipant = { - hotkey_principal : Text; - cf_neurons : [CfNeuron]; - }; - public type Change = { #ToRemove : NodeProvider; #ToAdd : NodeProvider }; - public type ChangeAutoStakeMaturity = { - requested_setting_for_auto_stake_maturity : Bool; - }; - public type ClaimOrRefresh = { by : ?By }; - public type ClaimOrRefreshNeuronFromAccount = { - controller : ?Principal; - memo : Nat64; - }; - public type ClaimOrRefreshNeuronFromAccountResponse = { result : ?Result_1 }; - public type ClaimOrRefreshResponse = { refreshed_neuron_id : ?NeuronId }; - public type Command = { - #Spawn : Spawn; - #Split : Split; - #Follow : Follow; - #ClaimOrRefresh : ClaimOrRefresh; - #Configure : Configure; - #RegisterVote : RegisterVote; - #Merge : Merge; - #DisburseToNeuron : DisburseToNeuron; - #MakeProposal : Proposal; - #StakeMaturity : StakeMaturity; - #MergeMaturity : MergeMaturity; - #Disburse : Disburse; - }; - public type Command_1 = { - #Error : GovernanceError; - #Spawn : SpawnResponse; - #Split : SpawnResponse; - #Follow : {}; - #ClaimOrRefresh : ClaimOrRefreshResponse; - #Configure : {}; - #RegisterVote : {}; - #Merge : MergeResponse; - #DisburseToNeuron : SpawnResponse; - #MakeProposal : MakeProposalResponse; - #StakeMaturity : StakeMaturityResponse; - #MergeMaturity : MergeMaturityResponse; - #Disburse : DisburseResponse; - }; - public type Command_2 = { - #Spawn : NeuronId; - #Split : Split; - #Configure : Configure; - #Merge : Merge; - #DisburseToNeuron : DisburseToNeuron; - #SyncCommand : {}; - #ClaimOrRefreshNeuron : ClaimOrRefresh; - #MergeMaturity : MergeMaturity; - #Disburse : Disburse; - }; - public type Committed = { - total_direct_contribution_icp_e8s : ?Nat64; - total_neurons_fund_contribution_icp_e8s : ?Nat64; - sns_governance_canister_id : ?Principal; - }; - public type Committed_1 = { - total_direct_participation_icp_e8s : ?Nat64; - total_neurons_fund_participation_icp_e8s : ?Nat64; - sns_governance_canister_id : ?Principal; - }; - public type Configure = { operation : ?Operation }; - public type Countries = { iso_codes : [Text] }; - public type CreateServiceNervousSystem = { - url : ?Text; - governance_parameters : ?GovernanceParameters; - fallback_controller_principal_ids : [Principal]; - logo : ?Image; - name : ?Text; - ledger_parameters : ?LedgerParameters; - description : ?Text; - dapp_canisters : [Canister]; - swap_parameters : ?SwapParameters; - initial_token_distribution : ?InitialTokenDistribution; - }; - public type DerivedProposalInformation = { - swap_background_information : ?SwapBackgroundInformation; - }; - public type DeveloperDistribution = { - developer_neurons : [NeuronDistribution]; - }; - public type Disburse = { to_account : ?AccountIdentifier; amount : ?Amount }; - public type DisburseResponse = { transfer_block_height : Nat64 }; - public type DisburseToNeuron = { - dissolve_delay_seconds : Nat64; - kyc_verified : Bool; - amount_e8s : Nat64; - new_controller : ?Principal; - nonce : Nat64; - }; - public type DissolveState = { - #DissolveDelaySeconds : Nat64; - #WhenDissolvedTimestampSeconds : Nat64; - }; - public type Duration = { seconds : ?Nat64 }; - public type ExecuteNnsFunction = { nns_function : Int32; payload : Blob }; - public type Follow = { topic : Int32; followees : [NeuronId] }; - public type Followees = { followees : [NeuronId] }; - public type Followers = { followers : [NeuronId] }; - public type FollowersMap = { followers_map : [(Nat64, Followers)] }; - public type GetNeuronsFundAuditInfoRequest = { nns_proposal_id : ?NeuronId }; - public type GetNeuronsFundAuditInfoResponse = { result : ?Result_6 }; - public type GlobalTimeOfDay = { seconds_after_utc_midnight : ?Nat64 }; - public type Governance = { - default_followees : [(Int32, Followees)]; - making_sns_proposal : ?MakingSnsProposal; - most_recent_monthly_node_provider_rewards : ?MostRecentMonthlyNodeProviderRewards; - maturity_modulation_last_updated_at_timestamp_seconds : ?Nat64; - wait_for_quiet_threshold_seconds : Nat64; - metrics : ?GovernanceCachedMetrics; - neuron_management_voting_period_seconds : ?Nat64; - node_providers : [NodeProvider]; - cached_daily_maturity_modulation_basis_points : ?Int32; - economics : ?NetworkEconomics; - spawning_neurons : ?Bool; - latest_reward_event : ?RewardEvent; - to_claim_transfers : [NeuronStakeTransfer]; - short_voting_period_seconds : Nat64; - topic_followee_index : [(Int32, FollowersMap)]; - migrations : ?Migrations; - proposals : [(Nat64, ProposalData)]; - in_flight_commands : [(Nat64, NeuronInFlightCommand)]; - neurons : [(Nat64, Neuron)]; - genesis_timestamp_seconds : Nat64; - }; - public type GovernanceCachedMetrics = { - total_maturity_e8s_equivalent : Nat64; - not_dissolving_neurons_e8s_buckets : [(Nat64, Float)]; - dissolving_neurons_staked_maturity_e8s_equivalent_sum : Nat64; - garbage_collectable_neurons_count : Nat64; - dissolving_neurons_staked_maturity_e8s_equivalent_buckets : [ - (Nat64, Float) - ]; - neurons_with_invalid_stake_count : Nat64; - not_dissolving_neurons_count_buckets : [(Nat64, Nat64)]; - ect_neuron_count : Nat64; - total_supply_icp : Nat64; - neurons_with_less_than_6_months_dissolve_delay_count : Nat64; - dissolved_neurons_count : Nat64; - community_fund_total_maturity_e8s_equivalent : Nat64; - total_staked_e8s_seed : Nat64; - total_staked_maturity_e8s_equivalent_ect : Nat64; - total_staked_e8s : Nat64; - not_dissolving_neurons_count : Nat64; - total_locked_e8s : Nat64; - neurons_fund_total_active_neurons : Nat64; - total_staked_maturity_e8s_equivalent : Nat64; - not_dissolving_neurons_e8s_buckets_ect : [(Nat64, Float)]; - total_staked_e8s_ect : Nat64; - not_dissolving_neurons_staked_maturity_e8s_equivalent_sum : Nat64; - dissolved_neurons_e8s : Nat64; - dissolving_neurons_e8s_buckets_seed : [(Nat64, Float)]; - neurons_with_less_than_6_months_dissolve_delay_e8s : Nat64; - not_dissolving_neurons_staked_maturity_e8s_equivalent_buckets : [ - (Nat64, Float) - ]; - dissolving_neurons_count_buckets : [(Nat64, Nat64)]; - dissolving_neurons_e8s_buckets_ect : [(Nat64, Float)]; - dissolving_neurons_count : Nat64; - dissolving_neurons_e8s_buckets : [(Nat64, Float)]; - total_staked_maturity_e8s_equivalent_seed : Nat64; - community_fund_total_staked_e8s : Nat64; - not_dissolving_neurons_e8s_buckets_seed : [(Nat64, Float)]; - timestamp_seconds : Nat64; - seed_neuron_count : Nat64; - }; - public type GovernanceError = { error_message : Text; error_type : Int32 }; - public type GovernanceParameters = { - neuron_maximum_dissolve_delay_bonus : ?Percentage; - neuron_maximum_age_for_age_bonus : ?Duration; - neuron_maximum_dissolve_delay : ?Duration; - neuron_minimum_dissolve_delay_to_vote : ?Duration; - neuron_maximum_age_bonus : ?Percentage; - neuron_minimum_stake : ?Tokens; - proposal_wait_for_quiet_deadline_increase : ?Duration; - proposal_initial_voting_period : ?Duration; - proposal_rejection_fee : ?Tokens; - voting_reward_parameters : ?VotingRewardParameters; - }; - public type IdealMatchedParticipationFunction = { - serialized_representation : ?Text; - }; - public type Image = { base64_encoding : ?Text }; - public type IncreaseDissolveDelay = { - additional_dissolve_delay_seconds : Nat32; - }; - public type InitialTokenDistribution = { - treasury_distribution : ?SwapDistribution; - developer_distribution : ?DeveloperDistribution; - swap_distribution : ?SwapDistribution; - }; - public type KnownNeuron = { - id : ?NeuronId; - known_neuron_data : ?KnownNeuronData; - }; - public type KnownNeuronData = { name : Text; description : ?Text }; - public type LedgerParameters = { - transaction_fee : ?Tokens; - token_symbol : ?Text; - token_logo : ?Image; - token_name : ?Text; - }; - public type ListKnownNeuronsResponse = { known_neurons : [KnownNeuron] }; - public type ListNeurons = { - neuron_ids : [Nat64]; - include_neurons_readable_by_caller : Bool; - }; - public type ListNeuronsResponse = { - neuron_infos : [(Nat64, NeuronInfo)]; - full_neurons : [Neuron]; - }; - public type ListNodeProvidersResponse = { node_providers : [NodeProvider] }; - public type ListProposalInfo = { - include_reward_status : [Int32]; - omit_large_fields : ?Bool; - before_proposal : ?NeuronId; - limit : Nat32; - exclude_topic : [Int32]; - include_all_manage_neuron_proposals : ?Bool; - include_status : [Int32]; - }; - public type ListProposalInfoResponse = { proposal_info : [ProposalInfo] }; - public type MakeProposalResponse = { - message : ?Text; - proposal_id : ?NeuronId; - }; - public type MakingSnsProposal = { - proposal : ?Proposal; - caller : ?Principal; - proposer_id : ?NeuronId; - }; - public type ManageNeuron = { - id : ?NeuronId; - command : ?Command; - neuron_id_or_subaccount : ?NeuronIdOrSubaccount; - }; - public type ManageNeuronResponse = { command : ?Command_1 }; - public type Merge = { source_neuron_id : ?NeuronId }; - public type MergeMaturity = { percentage_to_merge : Nat32 }; - public type MergeMaturityResponse = { - merged_maturity_e8s : Nat64; - new_stake_e8s : Nat64; - }; - public type MergeResponse = { - target_neuron : ?Neuron; - source_neuron : ?Neuron; - target_neuron_info : ?NeuronInfo; - source_neuron_info : ?NeuronInfo; - }; - public type Migration = { - status : ?Int32; - failure_reason : ?Text; - progress : ?Progress; - }; - public type Migrations = { - neuron_indexes_migration : ?Migration; - copy_inactive_neurons_to_stable_memory_migration : ?Migration; - }; - public type MostRecentMonthlyNodeProviderRewards = { - timestamp : Nat64; - rewards : [RewardNodeProvider]; - }; - public type Motion = { motion_text : Text }; - public type NetworkEconomics = { - neuron_minimum_stake_e8s : Nat64; - max_proposals_to_keep_per_topic : Nat32; - neuron_management_fee_per_proposal_e8s : Nat64; - reject_cost_e8s : Nat64; - transaction_fee_e8s : Nat64; - neuron_spawn_dissolve_delay_seconds : Nat64; - minimum_icp_xdr_rate : Nat64; - maximum_node_provider_rewards_e8s : Nat64; - }; - public type Neuron = { - id : ?NeuronId; - staked_maturity_e8s_equivalent : ?Nat64; - controller : ?Principal; - recent_ballots : [BallotInfo]; - kyc_verified : Bool; - neuron_type : ?Int32; - not_for_profit : Bool; - maturity_e8s_equivalent : Nat64; - cached_neuron_stake_e8s : Nat64; - created_timestamp_seconds : Nat64; - auto_stake_maturity : ?Bool; - aging_since_timestamp_seconds : Nat64; - hot_keys : [Principal]; - account : Blob; - joined_community_fund_timestamp_seconds : ?Nat64; - dissolve_state : ?DissolveState; - followees : [(Int32, Followees)]; - neuron_fees_e8s : Nat64; - transfer : ?NeuronStakeTransfer; - known_neuron_data : ?KnownNeuronData; - spawn_at_timestamp_seconds : ?Nat64; - }; - public type NeuronBasketConstructionParameters = { - dissolve_delay_interval : ?Duration; - count : ?Nat64; - }; - public type NeuronBasketConstructionParameters_1 = { - dissolve_delay_interval_seconds : Nat64; - count : Nat64; - }; - public type NeuronDistribution = { - controller : ?Principal; - dissolve_delay : ?Duration; - memo : ?Nat64; - vesting_period : ?Duration; - stake : ?Tokens; - }; - public type NeuronId = { id : Nat64 }; - public type NeuronIdOrSubaccount = { - #Subaccount : Blob; - #NeuronId : NeuronId; - }; - public type NeuronInFlightCommand = { - command : ?Command_2; - timestamp : Nat64; - }; - public type NeuronInfo = { - dissolve_delay_seconds : Nat64; - recent_ballots : [BallotInfo]; - neuron_type : ?Int32; - created_timestamp_seconds : Nat64; - state : Int32; - stake_e8s : Nat64; - joined_community_fund_timestamp_seconds : ?Nat64; - retrieved_at_timestamp_seconds : Nat64; - known_neuron_data : ?KnownNeuronData; - voting_power : Nat64; - age_seconds : Nat64; - }; - public type NeuronStakeTransfer = { - to_subaccount : Blob; - neuron_stake_e8s : Nat64; - from : ?Principal; - memo : Nat64; - from_subaccount : Blob; - transfer_timestamp : Nat64; - block_height : Nat64; - }; - public type NeuronsFundAuditInfo = { - final_neurons_fund_participation : ?NeuronsFundParticipation; - initial_neurons_fund_participation : ?NeuronsFundParticipation; - neurons_fund_refunds : ?NeuronsFundSnapshot; - }; - public type NeuronsFundData = { - final_neurons_fund_participation : ?NeuronsFundParticipation; - initial_neurons_fund_participation : ?NeuronsFundParticipation; - neurons_fund_refunds : ?NeuronsFundSnapshot; - }; - public type NeuronsFundNeuron = { - hotkey_principal : ?Text; - is_capped : ?Bool; - nns_neuron_id : ?Nat64; - amount_icp_e8s : ?Nat64; - }; - public type NeuronsFundNeuronPortion = { - hotkey_principal : ?Principal; - is_capped : ?Bool; - maturity_equivalent_icp_e8s : ?Nat64; - nns_neuron_id : ?NeuronId; - amount_icp_e8s : ?Nat64; - }; - public type NeuronsFundParticipation = { - total_maturity_equivalent_icp_e8s : ?Nat64; - intended_neurons_fund_participation_icp_e8s : ?Nat64; - direct_participation_icp_e8s : ?Nat64; - swap_participation_limits : ?SwapParticipationLimits; - max_neurons_fund_swap_participation_icp_e8s : ?Nat64; - neurons_fund_reserves : ?NeuronsFundSnapshot; - ideal_matched_participation_function : ?IdealMatchedParticipationFunction; - allocated_neurons_fund_participation_icp_e8s : ?Nat64; - }; - public type NeuronsFundSnapshot = { - neurons_fund_neuron_portions : [NeuronsFundNeuronPortion]; - }; - public type NodeProvider = { - id : ?Principal; - reward_account : ?AccountIdentifier; - }; - public type Ok = { neurons_fund_audit_info : ?NeuronsFundAuditInfo }; - public type Ok_1 = { neurons_fund_neuron_portions : [NeuronsFundNeuron] }; - public type OpenSnsTokenSwap = { - community_fund_investment_e8s : ?Nat64; - target_swap_canister_id : ?Principal; - params : ?Params; - }; - public type Operation = { - #RemoveHotKey : RemoveHotKey; - #AddHotKey : AddHotKey; - #ChangeAutoStakeMaturity : ChangeAutoStakeMaturity; - #StopDissolving : {}; - #StartDissolving : {}; - #IncreaseDissolveDelay : IncreaseDissolveDelay; - #JoinCommunityFund : {}; - #LeaveCommunityFund : {}; - #SetDissolveTimestamp : SetDissolveTimestamp; - }; - public type Params = { - min_participant_icp_e8s : Nat64; - neuron_basket_construction_parameters : ?NeuronBasketConstructionParameters_1; - max_icp_e8s : Nat64; - swap_due_timestamp_seconds : Nat64; - min_participants : Nat32; - sns_token_e8s : Nat64; - sale_delay_seconds : ?Nat64; - max_participant_icp_e8s : Nat64; - min_direct_participation_icp_e8s : ?Nat64; - min_icp_e8s : Nat64; - max_direct_participation_icp_e8s : ?Nat64; - }; - public type Percentage = { basis_points : ?Nat64 }; - public type Progress = { #LastNeuronId : NeuronId }; - public type Proposal = { - url : Text; - title : ?Text; - action : ?Action; - summary : Text; - }; - public type ProposalData = { - id : ?NeuronId; - failure_reason : ?GovernanceError; - cf_participants : [CfParticipant]; - ballots : [(Nat64, Ballot)]; - proposal_timestamp_seconds : Nat64; - reward_event_round : Nat64; - failed_timestamp_seconds : Nat64; - neurons_fund_data : ?NeuronsFundData; - reject_cost_e8s : Nat64; - derived_proposal_information : ?DerivedProposalInformation; - latest_tally : ?Tally; - sns_token_swap_lifecycle : ?Int32; - decided_timestamp_seconds : Nat64; - proposal : ?Proposal; - proposer : ?NeuronId; - wait_for_quiet_state : ?WaitForQuietState; - executed_timestamp_seconds : Nat64; - original_total_community_fund_maturity_e8s_equivalent : ?Nat64; - }; - public type ProposalInfo = { - id : ?NeuronId; - status : Int32; - topic : Int32; - failure_reason : ?GovernanceError; - ballots : [(Nat64, Ballot)]; - proposal_timestamp_seconds : Nat64; - reward_event_round : Nat64; - deadline_timestamp_seconds : ?Nat64; - failed_timestamp_seconds : Nat64; - reject_cost_e8s : Nat64; - derived_proposal_information : ?DerivedProposalInformation; - latest_tally : ?Tally; - reward_status : Int32; - decided_timestamp_seconds : Nat64; - proposal : ?Proposal; - proposer : ?NeuronId; - executed_timestamp_seconds : Nat64; - }; - public type RegisterVote = { vote : Int32; proposal : ?NeuronId }; - public type RemoveHotKey = { hot_key_to_remove : ?Principal }; - public type Result = { #Ok; #Err : GovernanceError }; - public type Result_1 = { #Error : GovernanceError; #NeuronId : NeuronId }; - public type Result_10 = { #Ok : Ok_1; #Err : GovernanceError }; - public type Result_2 = { #Ok : Neuron; #Err : GovernanceError }; - public type Result_3 = { - #Ok : GovernanceCachedMetrics; - #Err : GovernanceError; - }; - public type Result_4 = { #Ok : RewardNodeProviders; #Err : GovernanceError }; - public type Result_5 = { #Ok : NeuronInfo; #Err : GovernanceError }; - public type Result_6 = { #Ok : Ok; #Err : GovernanceError }; - public type Result_7 = { #Ok : NodeProvider; #Err : GovernanceError }; - public type Result_8 = { #Committed : Committed; #Aborted : {} }; - public type Result_9 = { #Committed : Committed_1; #Aborted : {} }; - public type RewardEvent = { - rounds_since_last_distribution : ?Nat64; - day_after_genesis : Nat64; - actual_timestamp_seconds : Nat64; - total_available_e8s_equivalent : Nat64; - latest_round_available_e8s_equivalent : ?Nat64; - distributed_e8s_equivalent : Nat64; - settled_proposals : [NeuronId]; - }; - public type RewardMode = { - #RewardToNeuron : RewardToNeuron; - #RewardToAccount : RewardToAccount; - }; - public type RewardNodeProvider = { - node_provider : ?NodeProvider; - reward_mode : ?RewardMode; - amount_e8s : Nat64; - }; - public type RewardNodeProviders = { - use_registry_derived_rewards : ?Bool; - rewards : [RewardNodeProvider]; - }; - public type RewardToAccount = { to_account : ?AccountIdentifier }; - public type RewardToNeuron = { dissolve_delay_seconds : Nat64 }; - public type SetDefaultFollowees = { - default_followees : [(Int32, Followees)]; - }; - public type SetDissolveTimestamp = { dissolve_timestamp_seconds : Nat64 }; - public type SetOpenTimeWindowRequest = { open_time_window : ?TimeWindow }; - public type SetSnsTokenSwapOpenTimeWindow = { - request : ?SetOpenTimeWindowRequest; - swap_canister_id : ?Principal; - }; - public type SettleCommunityFundParticipation = { - result : ?Result_8; - open_sns_token_swap_proposal_id : ?Nat64; - }; - public type SettleNeuronsFundParticipationRequest = { - result : ?Result_9; - nns_proposal_id : ?Nat64; - }; - public type SettleNeuronsFundParticipationResponse = { result : ?Result_10 }; - public type Spawn = { - percentage_to_spawn : ?Nat32; - new_controller : ?Principal; - nonce : ?Nat64; - }; - public type SpawnResponse = { created_neuron_id : ?NeuronId }; - public type Split = { amount_e8s : Nat64 }; - public type StakeMaturity = { percentage_to_stake : ?Nat32 }; - public type StakeMaturityResponse = { - maturity_e8s : Nat64; - staked_maturity_e8s : Nat64; - }; - public type SwapBackgroundInformation = { - ledger_index_canister_summary : ?CanisterSummary; - fallback_controller_principal_ids : [Principal]; - ledger_archive_canister_summaries : [CanisterSummary]; - ledger_canister_summary : ?CanisterSummary; - swap_canister_summary : ?CanisterSummary; - governance_canister_summary : ?CanisterSummary; - root_canister_summary : ?CanisterSummary; - dapp_canister_summaries : [CanisterSummary]; - }; - public type SwapDistribution = { total : ?Tokens }; - public type SwapParameters = { - minimum_participants : ?Nat64; - neurons_fund_participation : ?Bool; - duration : ?Duration; - neuron_basket_construction_parameters : ?NeuronBasketConstructionParameters; - confirmation_text : ?Text; - maximum_participant_icp : ?Tokens; - minimum_icp : ?Tokens; - minimum_direct_participation_icp : ?Tokens; - minimum_participant_icp : ?Tokens; - start_time : ?GlobalTimeOfDay; - maximum_direct_participation_icp : ?Tokens; - maximum_icp : ?Tokens; - neurons_fund_investment_icp : ?Tokens; - restricted_countries : ?Countries; - }; - public type SwapParticipationLimits = { - min_participant_icp_e8s : ?Nat64; - max_participant_icp_e8s : ?Nat64; - min_direct_participation_icp_e8s : ?Nat64; - max_direct_participation_icp_e8s : ?Nat64; - }; - public type Tally = { - no : Nat64; - yes : Nat64; - total : Nat64; - timestamp_seconds : Nat64; - }; - public type TimeWindow = { - start_timestamp_seconds : Nat64; - end_timestamp_seconds : Nat64; - }; - public type Tokens = { e8s : ?Nat64 }; - public type UpdateNodeProvider = { reward_account : ?AccountIdentifier }; - public type VotingRewardParameters = { - reward_rate_transition_duration : ?Duration; - initial_reward_rate : ?Percentage; - final_reward_rate : ?Percentage; - }; - public type WaitForQuietState = { - current_deadline_timestamp_seconds : Nat64; - }; - - public type NervousSystemFunction = { - id : Nat64; - name : Text; - description : ?Text; - //function_type : opt FunctionType; - }; - - public type ListNervousSystemFunctionsResponse = { - reserved_ids : [Nat64]; - functions : [NervousSystemFunction]; - }; - public type GovernanceCanister = actor { - //NNS - claim_gtc_neurons : shared (Principal, [NeuronId]) -> async Result; - claim_or_refresh_neuron_from_account : shared ClaimOrRefreshNeuronFromAccount -> async ClaimOrRefreshNeuronFromAccountResponse; - get_build_metadata : shared query () -> async Text; - get_full_neuron : shared query Nat64 -> async Result_2; - get_full_neuron_by_id_or_subaccount : shared query NeuronIdOrSubaccount -> async Result_2; - get_latest_reward_event : shared query () -> async RewardEvent; - get_metrics : shared query () -> async Result_3; - get_monthly_node_provider_rewards : shared () -> async Result_4; - get_most_recent_monthly_node_provider_rewards : shared query () -> async ?MostRecentMonthlyNodeProviderRewards; - get_network_economics_parameters : shared query () -> async NetworkEconomics; - get_neuron_ids : shared query () -> async [Nat64]; - get_neuron_info : shared query Nat64 -> async Result_5; - get_neuron_info_by_id_or_subaccount : shared query NeuronIdOrSubaccount -> async Result_5; - get_neurons_fund_audit_info : shared query GetNeuronsFundAuditInfoRequest -> async GetNeuronsFundAuditInfoResponse; - get_node_provider_by_caller : shared query Null -> async Result_7; - get_pending_proposals : shared query () -> async [ProposalInfo]; - get_proposal_info : shared query Nat64 -> async ?ProposalInfo; - list_known_neurons : shared query () -> async ListKnownNeuronsResponse; - list_neurons : shared query ListNeurons -> async ListNeuronsResponse; - list_node_providers : shared query () -> async ListNodeProvidersResponse; - list_proposals : shared query ListProposalInfo -> async ListProposalInfoResponse; - manage_neuron : shared ManageNeuron -> async ManageNeuronResponse; - settle_community_fund_participation : shared SettleCommunityFundParticipation -> async Result; - settle_neurons_fund_participation : shared SettleNeuronsFundParticipationRequest -> async SettleNeuronsFundParticipationResponse; - simulate_manage_neuron : shared ManageNeuron -> async ManageNeuronResponse; - transfer_gtc_neuron : shared (NeuronId, NeuronId) -> async Result; - update_node_provider : shared UpdateNodeProvider -> async Result; - - //SNS - get_metadata: shared query () -> async ( {url: ?Text; logo:?Text; name:?Text; description:?Text}); - list_nervous_system_functions : shared query () -> async(ListNervousSystemFunctionsResponse); - }; - - // public type GovernanceService ={ - // listProposals : (governanceId : Text, info : GT.ListProposalInfo) -> async* Result.Result; - - // }; -} \ No newline at end of file From aec633d15241efb3e92bcddbf702ead0b8da4783 Mon Sep 17 00:00:00 2001 From: Zane Date: Sun, 17 Nov 2024 16:51:26 +0100 Subject: [PATCH 05/11] CRUD methods for tally --- .../Governance/GovernanceService.mo | 2 + .../Governance/GovernanceTypes.mo | 689 ------------------ .../Proposal/ProposalService.mo | 2 - .../Tally/TallyService.mo | 194 ++++- .../Tally/TallyTypes.mo | 9 +- src/proposal_tracker_backend/main.mo | 190 +++-- 6 files changed, 282 insertions(+), 804 deletions(-) delete mode 100644 src/proposal_tracker_backend/Governance/GovernanceTypes.mo diff --git a/src/proposal_tracker_backend/Governance/GovernanceService.mo b/src/proposal_tracker_backend/Governance/GovernanceService.mo index 96bd2c8..9c2379c 100644 --- a/src/proposal_tracker_backend/Governance/GovernanceService.mo +++ b/src/proposal_tracker_backend/Governance/GovernanceService.mo @@ -13,6 +13,8 @@ import NNSTypes "../External_Canisters/NNS/NNSTypes"; import NNSMappings "../External_Canisters/NNS/NNSMappings"; import SNSTypes "../External_Canisters/SNS/SNSTypes"; + // TODO: separate functions and topics + // Reconciciliate NNS and SNS differences: (no active_proposals endpoint and topics instead of types) module { public class GovernanceService() { // let BATCH_SIZE_LIMIT = 50; diff --git a/src/proposal_tracker_backend/Governance/GovernanceTypes.mo b/src/proposal_tracker_backend/Governance/GovernanceTypes.mo deleted file mode 100644 index bf13a1c..0000000 --- a/src/proposal_tracker_backend/Governance/GovernanceTypes.mo +++ /dev/null @@ -1,689 +0,0 @@ -// This is a generated Motoko binding. -// Please use `import service "ic:canister_id"` instead to call canisters on the IC if possible. - -module { - public type AccountIdentifier = { hash : Blob }; - public type Action = { - #RegisterKnownNeuron : KnownNeuron; - #ManageNeuron : ManageNeuron; - #CreateServiceNervousSystem : CreateServiceNervousSystem; - #ExecuteNnsFunction : ExecuteNnsFunction; - #RewardNodeProvider : RewardNodeProvider; - #OpenSnsTokenSwap : OpenSnsTokenSwap; - #SetSnsTokenSwapOpenTimeWindow : SetSnsTokenSwapOpenTimeWindow; - #SetDefaultFollowees : SetDefaultFollowees; - #RewardNodeProviders : RewardNodeProviders; - #ManageNetworkEconomics : NetworkEconomics; - #ApproveGenesisKyc : ApproveGenesisKyc; - #AddOrRemoveNodeProvider : AddOrRemoveNodeProvider; - #Motion : Motion; - }; - public type AddHotKey = { new_hot_key : ?Principal }; - public type AddOrRemoveNodeProvider = { change : ?Change }; - public type Amount = { e8s : Nat64 }; - public type ApproveGenesisKyc = { principals : [Principal] }; - public type Ballot = { vote : Int32; voting_power : Nat64 }; - public type BallotInfo = { vote : Int32; proposal_id : ?NeuronId }; - public type By = { - #NeuronIdOrSubaccount : {}; - #MemoAndController : ClaimOrRefreshNeuronFromAccount; - #Memo : Nat64; - }; - public type Canister = { id : ?Principal }; - public type CanisterStatusResultV2 = { - status : ?Int32; - freezing_threshold : ?Nat64; - controllers : [Principal]; - memory_size : ?Nat64; - cycles : ?Nat64; - idle_cycles_burned_per_day : ?Nat64; - module_hash : Blob; - }; - public type CanisterSummary = { - status : ?CanisterStatusResultV2; - canister_id : ?Principal; - }; - public type CfNeuron = { - has_created_neuron_recipes : ?Bool; - nns_neuron_id : Nat64; - amount_icp_e8s : Nat64; - }; - public type CfParticipant = { - hotkey_principal : Text; - cf_neurons : [CfNeuron]; - }; - public type Change = { #ToRemove : NodeProvider; #ToAdd : NodeProvider }; - public type ChangeAutoStakeMaturity = { - requested_setting_for_auto_stake_maturity : Bool; - }; - public type ClaimOrRefresh = { by : ?By }; - public type ClaimOrRefreshNeuronFromAccount = { - controller : ?Principal; - memo : Nat64; - }; - public type ClaimOrRefreshNeuronFromAccountResponse = { result : ?Result_1 }; - public type ClaimOrRefreshResponse = { refreshed_neuron_id : ?NeuronId }; - public type Command = { - #Spawn : Spawn; - #Split : Split; - #Follow : Follow; - #ClaimOrRefresh : ClaimOrRefresh; - #Configure : Configure; - #RegisterVote : RegisterVote; - #Merge : Merge; - #DisburseToNeuron : DisburseToNeuron; - #MakeProposal : Proposal; - #StakeMaturity : StakeMaturity; - #MergeMaturity : MergeMaturity; - #Disburse : Disburse; - }; - public type Command_1 = { - #Error : GovernanceError; - #Spawn : SpawnResponse; - #Split : SpawnResponse; - #Follow : {}; - #ClaimOrRefresh : ClaimOrRefreshResponse; - #Configure : {}; - #RegisterVote : {}; - #Merge : MergeResponse; - #DisburseToNeuron : SpawnResponse; - #MakeProposal : MakeProposalResponse; - #StakeMaturity : StakeMaturityResponse; - #MergeMaturity : MergeMaturityResponse; - #Disburse : DisburseResponse; - }; - public type Command_2 = { - #Spawn : NeuronId; - #Split : Split; - #Configure : Configure; - #Merge : Merge; - #DisburseToNeuron : DisburseToNeuron; - #SyncCommand : {}; - #ClaimOrRefreshNeuron : ClaimOrRefresh; - #MergeMaturity : MergeMaturity; - #Disburse : Disburse; - }; - public type Committed = { - total_direct_contribution_icp_e8s : ?Nat64; - total_neurons_fund_contribution_icp_e8s : ?Nat64; - sns_governance_canister_id : ?Principal; - }; - public type Committed_1 = { - total_direct_participation_icp_e8s : ?Nat64; - total_neurons_fund_participation_icp_e8s : ?Nat64; - sns_governance_canister_id : ?Principal; - }; - public type Configure = { operation : ?Operation }; - public type Countries = { iso_codes : [Text] }; - public type CreateServiceNervousSystem = { - url : ?Text; - governance_parameters : ?GovernanceParameters; - fallback_controller_principal_ids : [Principal]; - logo : ?Image; - name : ?Text; - ledger_parameters : ?LedgerParameters; - description : ?Text; - dapp_canisters : [Canister]; - swap_parameters : ?SwapParameters; - initial_token_distribution : ?InitialTokenDistribution; - }; - public type DerivedProposalInformation = { - swap_background_information : ?SwapBackgroundInformation; - }; - public type DeveloperDistribution = { - developer_neurons : [NeuronDistribution]; - }; - public type Disburse = { to_account : ?AccountIdentifier; amount : ?Amount }; - public type DisburseResponse = { transfer_block_height : Nat64 }; - public type DisburseToNeuron = { - dissolve_delay_seconds : Nat64; - kyc_verified : Bool; - amount_e8s : Nat64; - new_controller : ?Principal; - nonce : Nat64; - }; - public type DissolveState = { - #DissolveDelaySeconds : Nat64; - #WhenDissolvedTimestampSeconds : Nat64; - }; - public type Duration = { seconds : ?Nat64 }; - public type ExecuteNnsFunction = { nns_function : Int32; payload : Blob }; - public type Follow = { topic : Int32; followees : [NeuronId] }; - public type Followees = { followees : [NeuronId] }; - public type Followers = { followers : [NeuronId] }; - public type FollowersMap = { followers_map : [(Nat64, Followers)] }; - public type GetNeuronsFundAuditInfoRequest = { nns_proposal_id : ?NeuronId }; - public type GetNeuronsFundAuditInfoResponse = { result : ?Result_6 }; - public type GlobalTimeOfDay = { seconds_after_utc_midnight : ?Nat64 }; - public type Governance = { - default_followees : [(Int32, Followees)]; - making_sns_proposal : ?MakingSnsProposal; - most_recent_monthly_node_provider_rewards : ?MostRecentMonthlyNodeProviderRewards; - maturity_modulation_last_updated_at_timestamp_seconds : ?Nat64; - wait_for_quiet_threshold_seconds : Nat64; - metrics : ?GovernanceCachedMetrics; - neuron_management_voting_period_seconds : ?Nat64; - node_providers : [NodeProvider]; - cached_daily_maturity_modulation_basis_points : ?Int32; - economics : ?NetworkEconomics; - spawning_neurons : ?Bool; - latest_reward_event : ?RewardEvent; - to_claim_transfers : [NeuronStakeTransfer]; - short_voting_period_seconds : Nat64; - topic_followee_index : [(Int32, FollowersMap)]; - migrations : ?Migrations; - proposals : [(Nat64, ProposalData)]; - in_flight_commands : [(Nat64, NeuronInFlightCommand)]; - neurons : [(Nat64, Neuron)]; - genesis_timestamp_seconds : Nat64; - }; - public type GovernanceCachedMetrics = { - total_maturity_e8s_equivalent : Nat64; - not_dissolving_neurons_e8s_buckets : [(Nat64, Float)]; - dissolving_neurons_staked_maturity_e8s_equivalent_sum : Nat64; - garbage_collectable_neurons_count : Nat64; - dissolving_neurons_staked_maturity_e8s_equivalent_buckets : [ - (Nat64, Float) - ]; - neurons_with_invalid_stake_count : Nat64; - not_dissolving_neurons_count_buckets : [(Nat64, Nat64)]; - ect_neuron_count : Nat64; - total_supply_icp : Nat64; - neurons_with_less_than_6_months_dissolve_delay_count : Nat64; - dissolved_neurons_count : Nat64; - community_fund_total_maturity_e8s_equivalent : Nat64; - total_staked_e8s_seed : Nat64; - total_staked_maturity_e8s_equivalent_ect : Nat64; - total_staked_e8s : Nat64; - not_dissolving_neurons_count : Nat64; - total_locked_e8s : Nat64; - neurons_fund_total_active_neurons : Nat64; - total_staked_maturity_e8s_equivalent : Nat64; - not_dissolving_neurons_e8s_buckets_ect : [(Nat64, Float)]; - total_staked_e8s_ect : Nat64; - not_dissolving_neurons_staked_maturity_e8s_equivalent_sum : Nat64; - dissolved_neurons_e8s : Nat64; - dissolving_neurons_e8s_buckets_seed : [(Nat64, Float)]; - neurons_with_less_than_6_months_dissolve_delay_e8s : Nat64; - not_dissolving_neurons_staked_maturity_e8s_equivalent_buckets : [ - (Nat64, Float) - ]; - dissolving_neurons_count_buckets : [(Nat64, Nat64)]; - dissolving_neurons_e8s_buckets_ect : [(Nat64, Float)]; - dissolving_neurons_count : Nat64; - dissolving_neurons_e8s_buckets : [(Nat64, Float)]; - total_staked_maturity_e8s_equivalent_seed : Nat64; - community_fund_total_staked_e8s : Nat64; - not_dissolving_neurons_e8s_buckets_seed : [(Nat64, Float)]; - timestamp_seconds : Nat64; - seed_neuron_count : Nat64; - }; - public type GovernanceError = { error_message : Text; error_type : Int32 }; - public type GovernanceParameters = { - neuron_maximum_dissolve_delay_bonus : ?Percentage; - neuron_maximum_age_for_age_bonus : ?Duration; - neuron_maximum_dissolve_delay : ?Duration; - neuron_minimum_dissolve_delay_to_vote : ?Duration; - neuron_maximum_age_bonus : ?Percentage; - neuron_minimum_stake : ?Tokens; - proposal_wait_for_quiet_deadline_increase : ?Duration; - proposal_initial_voting_period : ?Duration; - proposal_rejection_fee : ?Tokens; - voting_reward_parameters : ?VotingRewardParameters; - }; - public type IdealMatchedParticipationFunction = { - serialized_representation : ?Text; - }; - public type Image = { base64_encoding : ?Text }; - public type IncreaseDissolveDelay = { - additional_dissolve_delay_seconds : Nat32; - }; - public type InitialTokenDistribution = { - treasury_distribution : ?SwapDistribution; - developer_distribution : ?DeveloperDistribution; - swap_distribution : ?SwapDistribution; - }; - public type KnownNeuron = { - id : ?NeuronId; - known_neuron_data : ?KnownNeuronData; - }; - public type KnownNeuronData = { name : Text; description : ?Text }; - public type LedgerParameters = { - transaction_fee : ?Tokens; - token_symbol : ?Text; - token_logo : ?Image; - token_name : ?Text; - }; - public type ListKnownNeuronsResponse = { known_neurons : [KnownNeuron] }; - public type ListNeurons = { - neuron_ids : [Nat64]; - include_neurons_readable_by_caller : Bool; - }; - public type ListNeuronsResponse = { - neuron_infos : [(Nat64, NeuronInfo)]; - full_neurons : [Neuron]; - }; - public type ListNodeProvidersResponse = { node_providers : [NodeProvider] }; - public type ListProposalInfo = { - include_reward_status : [Int32]; - omit_large_fields : ?Bool; - before_proposal : ?NeuronId; - limit : Nat32; - exclude_topic : [Int32]; - include_all_manage_neuron_proposals : ?Bool; - include_status : [Int32]; - }; - public type ListProposalInfoResponse = { proposal_info : [ProposalInfo] }; - public type MakeProposalResponse = { - message : ?Text; - proposal_id : ?NeuronId; - }; - public type MakingSnsProposal = { - proposal : ?Proposal; - caller : ?Principal; - proposer_id : ?NeuronId; - }; - public type ManageNeuron = { - id : ?NeuronId; - command : ?Command; - neuron_id_or_subaccount : ?NeuronIdOrSubaccount; - }; - public type ManageNeuronResponse = { command : ?Command_1 }; - public type Merge = { source_neuron_id : ?NeuronId }; - public type MergeMaturity = { percentage_to_merge : Nat32 }; - public type MergeMaturityResponse = { - merged_maturity_e8s : Nat64; - new_stake_e8s : Nat64; - }; - public type MergeResponse = { - target_neuron : ?Neuron; - source_neuron : ?Neuron; - target_neuron_info : ?NeuronInfo; - source_neuron_info : ?NeuronInfo; - }; - public type Migration = { - status : ?Int32; - failure_reason : ?Text; - progress : ?Progress; - }; - public type Migrations = { - neuron_indexes_migration : ?Migration; - copy_inactive_neurons_to_stable_memory_migration : ?Migration; - }; - public type MostRecentMonthlyNodeProviderRewards = { - timestamp : Nat64; - rewards : [RewardNodeProvider]; - }; - public type Motion = { motion_text : Text }; - public type NetworkEconomics = { - neuron_minimum_stake_e8s : Nat64; - max_proposals_to_keep_per_topic : Nat32; - neuron_management_fee_per_proposal_e8s : Nat64; - reject_cost_e8s : Nat64; - transaction_fee_e8s : Nat64; - neuron_spawn_dissolve_delay_seconds : Nat64; - minimum_icp_xdr_rate : Nat64; - maximum_node_provider_rewards_e8s : Nat64; - }; - public type Neuron = { - id : ?NeuronId; - staked_maturity_e8s_equivalent : ?Nat64; - controller : ?Principal; - recent_ballots : [BallotInfo]; - kyc_verified : Bool; - neuron_type : ?Int32; - not_for_profit : Bool; - maturity_e8s_equivalent : Nat64; - cached_neuron_stake_e8s : Nat64; - created_timestamp_seconds : Nat64; - auto_stake_maturity : ?Bool; - aging_since_timestamp_seconds : Nat64; - hot_keys : [Principal]; - account : Blob; - joined_community_fund_timestamp_seconds : ?Nat64; - dissolve_state : ?DissolveState; - followees : [(Int32, Followees)]; - neuron_fees_e8s : Nat64; - transfer : ?NeuronStakeTransfer; - known_neuron_data : ?KnownNeuronData; - spawn_at_timestamp_seconds : ?Nat64; - }; - public type NeuronBasketConstructionParameters = { - dissolve_delay_interval : ?Duration; - count : ?Nat64; - }; - public type NeuronBasketConstructionParameters_1 = { - dissolve_delay_interval_seconds : Nat64; - count : Nat64; - }; - public type NeuronDistribution = { - controller : ?Principal; - dissolve_delay : ?Duration; - memo : ?Nat64; - vesting_period : ?Duration; - stake : ?Tokens; - }; - public type NeuronId = { id : Nat64 }; - public type NeuronIdOrSubaccount = { - #Subaccount : Blob; - #NeuronId : NeuronId; - }; - public type NeuronInFlightCommand = { - command : ?Command_2; - timestamp : Nat64; - }; - public type NeuronInfo = { - dissolve_delay_seconds : Nat64; - recent_ballots : [BallotInfo]; - neuron_type : ?Int32; - created_timestamp_seconds : Nat64; - state : Int32; - stake_e8s : Nat64; - joined_community_fund_timestamp_seconds : ?Nat64; - retrieved_at_timestamp_seconds : Nat64; - known_neuron_data : ?KnownNeuronData; - voting_power : Nat64; - age_seconds : Nat64; - }; - public type NeuronStakeTransfer = { - to_subaccount : Blob; - neuron_stake_e8s : Nat64; - from : ?Principal; - memo : Nat64; - from_subaccount : Blob; - transfer_timestamp : Nat64; - block_height : Nat64; - }; - public type NeuronsFundAuditInfo = { - final_neurons_fund_participation : ?NeuronsFundParticipation; - initial_neurons_fund_participation : ?NeuronsFundParticipation; - neurons_fund_refunds : ?NeuronsFundSnapshot; - }; - public type NeuronsFundData = { - final_neurons_fund_participation : ?NeuronsFundParticipation; - initial_neurons_fund_participation : ?NeuronsFundParticipation; - neurons_fund_refunds : ?NeuronsFundSnapshot; - }; - public type NeuronsFundNeuron = { - hotkey_principal : ?Text; - is_capped : ?Bool; - nns_neuron_id : ?Nat64; - amount_icp_e8s : ?Nat64; - }; - public type NeuronsFundNeuronPortion = { - hotkey_principal : ?Principal; - is_capped : ?Bool; - maturity_equivalent_icp_e8s : ?Nat64; - nns_neuron_id : ?NeuronId; - amount_icp_e8s : ?Nat64; - }; - public type NeuronsFundParticipation = { - total_maturity_equivalent_icp_e8s : ?Nat64; - intended_neurons_fund_participation_icp_e8s : ?Nat64; - direct_participation_icp_e8s : ?Nat64; - swap_participation_limits : ?SwapParticipationLimits; - max_neurons_fund_swap_participation_icp_e8s : ?Nat64; - neurons_fund_reserves : ?NeuronsFundSnapshot; - ideal_matched_participation_function : ?IdealMatchedParticipationFunction; - allocated_neurons_fund_participation_icp_e8s : ?Nat64; - }; - public type NeuronsFundSnapshot = { - neurons_fund_neuron_portions : [NeuronsFundNeuronPortion]; - }; - public type NodeProvider = { - id : ?Principal; - reward_account : ?AccountIdentifier; - }; - public type Ok = { neurons_fund_audit_info : ?NeuronsFundAuditInfo }; - public type Ok_1 = { neurons_fund_neuron_portions : [NeuronsFundNeuron] }; - public type OpenSnsTokenSwap = { - community_fund_investment_e8s : ?Nat64; - target_swap_canister_id : ?Principal; - params : ?Params; - }; - public type Operation = { - #RemoveHotKey : RemoveHotKey; - #AddHotKey : AddHotKey; - #ChangeAutoStakeMaturity : ChangeAutoStakeMaturity; - #StopDissolving : {}; - #StartDissolving : {}; - #IncreaseDissolveDelay : IncreaseDissolveDelay; - #JoinCommunityFund : {}; - #LeaveCommunityFund : {}; - #SetDissolveTimestamp : SetDissolveTimestamp; - }; - public type Params = { - min_participant_icp_e8s : Nat64; - neuron_basket_construction_parameters : ?NeuronBasketConstructionParameters_1; - max_icp_e8s : Nat64; - swap_due_timestamp_seconds : Nat64; - min_participants : Nat32; - sns_token_e8s : Nat64; - sale_delay_seconds : ?Nat64; - max_participant_icp_e8s : Nat64; - min_direct_participation_icp_e8s : ?Nat64; - min_icp_e8s : Nat64; - max_direct_participation_icp_e8s : ?Nat64; - }; - public type Percentage = { basis_points : ?Nat64 }; - public type Progress = { #LastNeuronId : NeuronId }; - public type Proposal = { - url : Text; - title : ?Text; - action : ?Action; - summary : Text; - }; - public type ProposalData = { - id : ?NeuronId; - failure_reason : ?GovernanceError; - cf_participants : [CfParticipant]; - ballots : [(Nat64, Ballot)]; - proposal_timestamp_seconds : Nat64; - reward_event_round : Nat64; - failed_timestamp_seconds : Nat64; - neurons_fund_data : ?NeuronsFundData; - reject_cost_e8s : Nat64; - derived_proposal_information : ?DerivedProposalInformation; - latest_tally : ?Tally; - sns_token_swap_lifecycle : ?Int32; - decided_timestamp_seconds : Nat64; - proposal : ?Proposal; - proposer : ?NeuronId; - wait_for_quiet_state : ?WaitForQuietState; - executed_timestamp_seconds : Nat64; - original_total_community_fund_maturity_e8s_equivalent : ?Nat64; - }; - public type ProposalInfo = { - id : ?NeuronId; - status : Int32; - topic : Int32; - failure_reason : ?GovernanceError; - ballots : [(Nat64, Ballot)]; - proposal_timestamp_seconds : Nat64; - reward_event_round : Nat64; - deadline_timestamp_seconds : ?Nat64; - failed_timestamp_seconds : Nat64; - reject_cost_e8s : Nat64; - derived_proposal_information : ?DerivedProposalInformation; - latest_tally : ?Tally; - reward_status : Int32; - decided_timestamp_seconds : Nat64; - proposal : ?Proposal; - proposer : ?NeuronId; - executed_timestamp_seconds : Nat64; - }; - public type RegisterVote = { vote : Int32; proposal : ?NeuronId }; - public type RemoveHotKey = { hot_key_to_remove : ?Principal }; - public type Result = { #Ok; #Err : GovernanceError }; - public type Result_1 = { #Error : GovernanceError; #NeuronId : NeuronId }; - public type Result_10 = { #Ok : Ok_1; #Err : GovernanceError }; - public type Result_2 = { #Ok : Neuron; #Err : GovernanceError }; - public type Result_3 = { - #Ok : GovernanceCachedMetrics; - #Err : GovernanceError; - }; - public type Result_4 = { #Ok : RewardNodeProviders; #Err : GovernanceError }; - public type Result_5 = { #Ok : NeuronInfo; #Err : GovernanceError }; - public type Result_6 = { #Ok : Ok; #Err : GovernanceError }; - public type Result_7 = { #Ok : NodeProvider; #Err : GovernanceError }; - public type Result_8 = { #Committed : Committed; #Aborted : {} }; - public type Result_9 = { #Committed : Committed_1; #Aborted : {} }; - public type RewardEvent = { - rounds_since_last_distribution : ?Nat64; - day_after_genesis : Nat64; - actual_timestamp_seconds : Nat64; - total_available_e8s_equivalent : Nat64; - latest_round_available_e8s_equivalent : ?Nat64; - distributed_e8s_equivalent : Nat64; - settled_proposals : [NeuronId]; - }; - public type RewardMode = { - #RewardToNeuron : RewardToNeuron; - #RewardToAccount : RewardToAccount; - }; - public type RewardNodeProvider = { - node_provider : ?NodeProvider; - reward_mode : ?RewardMode; - amount_e8s : Nat64; - }; - public type RewardNodeProviders = { - use_registry_derived_rewards : ?Bool; - rewards : [RewardNodeProvider]; - }; - public type RewardToAccount = { to_account : ?AccountIdentifier }; - public type RewardToNeuron = { dissolve_delay_seconds : Nat64 }; - public type SetDefaultFollowees = { - default_followees : [(Int32, Followees)]; - }; - public type SetDissolveTimestamp = { dissolve_timestamp_seconds : Nat64 }; - public type SetOpenTimeWindowRequest = { open_time_window : ?TimeWindow }; - public type SetSnsTokenSwapOpenTimeWindow = { - request : ?SetOpenTimeWindowRequest; - swap_canister_id : ?Principal; - }; - public type SettleCommunityFundParticipation = { - result : ?Result_8; - open_sns_token_swap_proposal_id : ?Nat64; - }; - public type SettleNeuronsFundParticipationRequest = { - result : ?Result_9; - nns_proposal_id : ?Nat64; - }; - public type SettleNeuronsFundParticipationResponse = { result : ?Result_10 }; - public type Spawn = { - percentage_to_spawn : ?Nat32; - new_controller : ?Principal; - nonce : ?Nat64; - }; - public type SpawnResponse = { created_neuron_id : ?NeuronId }; - public type Split = { amount_e8s : Nat64 }; - public type StakeMaturity = { percentage_to_stake : ?Nat32 }; - public type StakeMaturityResponse = { - maturity_e8s : Nat64; - staked_maturity_e8s : Nat64; - }; - public type SwapBackgroundInformation = { - ledger_index_canister_summary : ?CanisterSummary; - fallback_controller_principal_ids : [Principal]; - ledger_archive_canister_summaries : [CanisterSummary]; - ledger_canister_summary : ?CanisterSummary; - swap_canister_summary : ?CanisterSummary; - governance_canister_summary : ?CanisterSummary; - root_canister_summary : ?CanisterSummary; - dapp_canister_summaries : [CanisterSummary]; - }; - public type SwapDistribution = { total : ?Tokens }; - public type SwapParameters = { - minimum_participants : ?Nat64; - neurons_fund_participation : ?Bool; - duration : ?Duration; - neuron_basket_construction_parameters : ?NeuronBasketConstructionParameters; - confirmation_text : ?Text; - maximum_participant_icp : ?Tokens; - minimum_icp : ?Tokens; - minimum_direct_participation_icp : ?Tokens; - minimum_participant_icp : ?Tokens; - start_time : ?GlobalTimeOfDay; - maximum_direct_participation_icp : ?Tokens; - maximum_icp : ?Tokens; - neurons_fund_investment_icp : ?Tokens; - restricted_countries : ?Countries; - }; - public type SwapParticipationLimits = { - min_participant_icp_e8s : ?Nat64; - max_participant_icp_e8s : ?Nat64; - min_direct_participation_icp_e8s : ?Nat64; - max_direct_participation_icp_e8s : ?Nat64; - }; - public type Tally = { - no : Nat64; - yes : Nat64; - total : Nat64; - timestamp_seconds : Nat64; - }; - public type TimeWindow = { - start_timestamp_seconds : Nat64; - end_timestamp_seconds : Nat64; - }; - public type Tokens = { e8s : ?Nat64 }; - public type UpdateNodeProvider = { reward_account : ?AccountIdentifier }; - public type VotingRewardParameters = { - reward_rate_transition_duration : ?Duration; - initial_reward_rate : ?Percentage; - final_reward_rate : ?Percentage; - }; - public type WaitForQuietState = { - current_deadline_timestamp_seconds : Nat64; - }; - - public type NervousSystemFunction = { - id : Nat64; - name : Text; - description : ?Text; - //function_type : opt FunctionType; - }; - - public type ListNervousSystemFunctionsResponse = { - reserved_ids : [Nat64]; - functions : [NervousSystemFunction]; - }; - public type GovernanceCanister = actor { - //NNS - claim_gtc_neurons : shared (Principal, [NeuronId]) -> async Result; - claim_or_refresh_neuron_from_account : shared ClaimOrRefreshNeuronFromAccount -> async ClaimOrRefreshNeuronFromAccountResponse; - get_build_metadata : shared query () -> async Text; - get_full_neuron : shared query Nat64 -> async Result_2; - get_full_neuron_by_id_or_subaccount : shared query NeuronIdOrSubaccount -> async Result_2; - get_latest_reward_event : shared query () -> async RewardEvent; - get_metrics : shared query () -> async Result_3; - get_monthly_node_provider_rewards : shared () -> async Result_4; - get_most_recent_monthly_node_provider_rewards : shared query () -> async ?MostRecentMonthlyNodeProviderRewards; - get_network_economics_parameters : shared query () -> async NetworkEconomics; - get_neuron_ids : shared query () -> async [Nat64]; - get_neuron_info : shared query Nat64 -> async Result_5; - get_neuron_info_by_id_or_subaccount : shared query NeuronIdOrSubaccount -> async Result_5; - get_neurons_fund_audit_info : shared query GetNeuronsFundAuditInfoRequest -> async GetNeuronsFundAuditInfoResponse; - get_node_provider_by_caller : shared query Null -> async Result_7; - get_pending_proposals : shared query () -> async [ProposalInfo]; - get_proposal_info : shared query Nat64 -> async ?ProposalInfo; - list_known_neurons : shared query () -> async ListKnownNeuronsResponse; - list_neurons : shared query ListNeurons -> async ListNeuronsResponse; - list_node_providers : shared query () -> async ListNodeProvidersResponse; - list_proposals : shared query ListProposalInfo -> async ListProposalInfoResponse; - manage_neuron : shared ManageNeuron -> async ManageNeuronResponse; - settle_community_fund_participation : shared SettleCommunityFundParticipation -> async Result; - settle_neurons_fund_participation : shared SettleNeuronsFundParticipationRequest -> async SettleNeuronsFundParticipationResponse; - simulate_manage_neuron : shared ManageNeuron -> async ManageNeuronResponse; - transfer_gtc_neuron : shared (NeuronId, NeuronId) -> async Result; - update_node_provider : shared UpdateNodeProvider -> async Result; - - //SNS - get_metadata: shared query () -> async ( {url: ?Text; logo:?Text; name:?Text; description:?Text}); - list_nervous_system_functions : shared query () -> async(ListNervousSystemFunctionsResponse); - }; - - // public type GovernanceService ={ - // listProposals : (governanceId : Text, info : GT.ListProposalInfo) -> async* Result.Result; - - // }; -} \ No newline at end of file diff --git a/src/proposal_tracker_backend/Proposal/ProposalService.mo b/src/proposal_tracker_backend/Proposal/ProposalService.mo index 65403bc..b394fa7 100644 --- a/src/proposal_tracker_backend/Proposal/ProposalService.mo +++ b/src/proposal_tracker_backend/Proposal/ProposalService.mo @@ -10,8 +10,6 @@ import Int64 "mo:base/Int64"; import Nat64 "mo:base/Nat64"; import Option "mo:base/Option"; import Utils "../utils"; - // TODO: separate functions and topics - // Reconciciliate NNS and SNS differences: (no active_proposals endpoint and topics instead of types) module{ let BATCH_SIZE_LIMIT = 50; diff --git a/src/proposal_tracker_backend/Tally/TallyService.mo b/src/proposal_tracker_backend/Tally/TallyService.mo index cfc9492..5034382 100644 --- a/src/proposal_tracker_backend/Tally/TallyService.mo +++ b/src/proposal_tracker_backend/Tally/TallyService.mo @@ -44,25 +44,25 @@ module { type NeuronId = TallyTypes.NeuronId; type TallyId = TallyTypes.TallyId; type ProposalId = TallyTypes.ProposalId; + type TopicId = TallyTypes.TopicId; type NeuronData = { id : NeuronId; - tallies : List.List; - topics : Map.Map; + topics : Map.Map; }; type TallyData = { id : TallyId; alias : ?Text; governanceCanister : Text; - topics : Map.Map; - neurons : Map.Map; + var topics : Map.Map; + var neurons : Map.Map; }; type Proposal = { id : ProposalId; isSettled : Bool; - topicId : Int32; + topicId : TopicId; ballots : Map.Map; settledTimestamp : ?Time.Time; }; @@ -157,12 +157,17 @@ module { let tallyId : Text = Nat.toText(tallyModel.lastId + 1); tallyModel.lastId := tallyModel.lastId + 1; let topicSet = Utils.arrayToSet(args.topics, i32hash); - let tally : TallyData = {id = tallyId; alias = args.alias; governanceCanister = governanceId; topics = topicSet; neurons = Utils.arrayToSet(args.neurons, n64hash); ballots = Map.new()}; + let tally : TallyData = {id = tallyId; alias = args.alias; governanceCanister = governanceId; var topics = topicSet; var neurons = Utils.arrayToSet(args.neurons, thash); ballots = Map.new()}; let tallyMap = Utils.getElseCreate(tallyModel.tallies, thash, governanceId, Map.new()); Map.set(tallyMap, thash, tallyId, tally); - - let subTallies = Utils.getElseCreate(tallyModel.subscribers, phash, args.subscriber, List.nil()); - Map.set(tallyModel.subscribers, phash, args.subscriber, List.push(tally, subTallies)); + + switch(args.subscriber){ + case(?subscriber){ + let subTallies = Utils.getElseCreate(tallyModel.subscribers, phash, subscriber, List.nil()); + Map.set(tallyModel.subscribers, phash, subscriber, List.push(tally, subTallies)); + }; + case(_){}; + }; Map.set(tallyModel.talliesById, thash, tallyId, tally); @@ -170,27 +175,28 @@ module { let neuronMap = Utils.getElseCreate(tallyModel.neurons, thash, governanceId, Map.new()); let tallyByNeuronMap = Utils.getElseCreate(tallyModel.talliesByNeuron, thash, governanceId, Map.new>()); for(neuronId in args.neurons.vals()){ - switch(Map.get(neuronMap, n64hash, neuronId)){ + switch(Map.get(neuronMap, thash, neuronId)){ case(?neuron) { for(topic in Map.keys(topicSet)){ Map.set(neuron.topics, i32hash, topic, ()); }; - Map.set(neuronMap, n64hash, neuronId, {neuron with tallies = List.push(tallyId, neuron.tallies)}); + //Map.set(neuronMap, thash, neuronId, {neuron with tallies = List.push(tallyId, neuron.tallies)}); }; case(_){ - Map.set(neuronMap, n64hash, neuronId, {id = neuronId; topics = topicSet; tallies = List.push(tallyId, List.nil())}); + //Map.set(neuronMap, thash, neuronId, {id = neuronId; topics = topicSet; tallies = List.push(tallyId, List.nil())}); + Map.set(neuronMap, thash, neuronId, {id = neuronId; topics = topicSet;}); }; }; - switch(Map.get(tallyByNeuronMap, n64hash, neuronId)){ + switch(Map.get(tallyByNeuronMap, thash, neuronId)){ case(?tallies) { - Map.set(tallyByNeuronMap, n64hash, neuronId, List.push(tally, tallies)); + Map.set(tallyByNeuronMap, thash, neuronId, List.push(tally, tallies)); }; case(_){ var tallyList = List.nil(); tallyList := List.push(tally, tallyList); - Map.set(tallyByNeuronMap, n64hash, neuronId, tallyList); + Map.set(tallyByNeuronMap, thash, neuronId, tallyList); }; } }; @@ -202,6 +208,122 @@ module { Map.get(tallyModel.talliesById, thash, tallyId); }; + func deleteNeuron(governanceId : GovernanceId, neuronId : NeuronId) : () { + switch(Map.get(tallyModel.neurons, thash, governanceId)){ + case(?neuronMap){ + Map.delete(neuronMap, thash, neuronId); + }; + case(_){}; + }; + }; + + public func deleteTally(tallyId : TallyId) : Result.Result<(), Text> { + if(updateState == #Running){ + return #err("Tallies are being updated, deleting could cause issues with global state"); + }; + + let #ok(tally) = Utils.optToRes(getTally(tallyId)) else {return #err("Tally not found")}; + Map.delete(tallyModel.talliesById, thash, tallyId); + + for ((sub, tally) in Map.entries(tallyModel.subscribers)){ + Map.set(tallyModel.subscribers, phash, sub, List.filter(tally, func(t : TallyData) : Bool {t.id != tallyId})); + }; + + switch(Map.get(tallyModel.talliesByNeuron, thash, tally.governanceCanister)){ + case(?neurons){ + for(neuronId in Map.keys(neurons)){ + switch(Map.get(neurons, thash, neuronId)){ + case(?tallies){ + let newList = List.filter(tallies, func(t : TallyData) : Bool {t.id != tallyId}); + //If no tallies depend on this neuron anymore it should be deleted. + if(List.size(newList) == 0){ + deleteNeuron(tally.governanceCanister, neuronId); + } else { + Map.set(neurons, thash, neuronId, newList); + }; + }; + case(_){}; + }; + }; + }; + case(_){}; + }; + + + switch(Map.get(tallyModel.tallies, thash, tally.governanceCanister)){ + case(?tallies){ + Map.delete(tallies, thash, tallyId); + }; + case(_){}; + }; + + + #ok() + }; + + public func addSubscriber(subscriber : Principal, tallyId : TallyId) : Result.Result<(), Text> { + let #ok(tally) = Utils.optToRes(getTally(tallyId)) else {return #err("Tally not found")}; + + let subTallies = Utils.getElseCreate(tallyModel.subscribers, phash, subscriber, List.nil()); + Map.set(tallyModel.subscribers, phash, subscriber, List.push(tally, subTallies)); + #ok() + }; + + public func deleteSubscriber(subscriber : Principal, tallyId : TallyId) : Result.Result<(), Text> { + switch(Map.get(tallyModel.subscribers, phash, subscriber)){ + case(?tallies){ + let newTallies = List.filter(tallies, func(tally : TallyData) : Bool { + return tally.id != tallyId; + }); + Map.set(tallyModel.subscribers, phash, subscriber, newTallies); + #ok() + }; + case(_){ + return #err("No subscriber found"); + }; + } + }; + + public func updateTally(tallyId : TallyId, newTally : {topics : [TopicId]; neurons : [NeuronId] }) : Result.Result<(), Text> { + if(updateState == #Running){ + return #err("Tallies are being updated, deleting could cause issues with global state"); + }; + + let #ok(tally) = Utils.optToRes(getTally(tallyId)) else {return #err("Tally not found")}; + let topicSet = Utils.arrayToSet(newTally.topics, i32hash); + let neuronSet = Utils.arrayToSet(newTally.neurons, thash); + + tally.topics := topicSet; + tally.neurons := neuronSet; + + + + #ok() + }; + + public func getSubscribersByTallyId(tallyId : TallyId) : [Principal]{ + let buf = Buffer.Buffer(20); + for((sub, tallies) in Map.entries(tallyModel.subscribers)){ + for(tally in List.toIter(tallies)){ + if(tally.id == tallyId){ + buf.add(sub); + }; + }; + }; + + Buffer.toArray(buf); + }; + + public func getTalliesByPrincipal(principal : Principal) : Result.Result<[TallyData], Text> { + switch(Map.get(tallyModel.subscribers, phash, principal)){ + case(?tallies){ + #ok(List.toArray(tallies)) + }; + case(_){ + return #err("No tallies found") + }; + }; + }; //TODO: change public func fetchProposalsAndUpdate() : async* (){ @@ -295,7 +417,7 @@ module { case(#ok(neurons)) { for(neuron in neurons.neuron_infos.vals()){ //process proposals whose ballots changes for this neuron if any - let proposalDelta = getProposalDeltaAndUpdateState(governanceId, neuron.0, neuron.1.recent_ballots, proposals, settledProposals); + let proposalDelta = getProposalDeltaAndUpdateState(governanceId, Nat64.toText(neuron.0), neuron.1.recent_ballots, proposals, settledProposals); if(List.size(proposalDelta.1) > 0){ delta := List.push(proposalDelta, delta); }; @@ -343,7 +465,7 @@ module { }; // - switch(Map.get(proposal.ballots, n64hash, neuronId)){ + switch(Map.get(proposal.ballots, thash, neuronId)){ case(?vote) { let newVote = NNSMappings.tryMapVoteFromInt(ballot.vote); switch(newVote){ @@ -351,11 +473,11 @@ module { if(vote != mapVote(mappedBallotVote, proposal.isSettled)){ proposalDelta := List.push(proposal.id, proposalDelta); let v = mapVote(mappedBallotVote, proposal.isSettled); - Map.set(proposal.ballots, n64hash, neuronId, v); + Map.set(proposal.ballots, thash, neuronId, v); }; }; case(#err(e)){ - logService.logError("Failed to map vote for proposal: " # Nat64.toText(proposal.id) # "for neuron: " # Nat64.toText(neuronId) # " error " # e, ?"[getProposalDeltaAndUpdateState]"); + logService.logError("Failed to map vote for proposal: " # Nat64.toText(proposal.id) # "for neuron: " # neuronId # " error " # e, ?"[getProposalDeltaAndUpdateState]"); }; }; }; @@ -364,11 +486,11 @@ module { switch(vote){ case(#ok(mappedBallotVote)){ let v = mapVote(mappedBallotVote, proposal.isSettled); - Map.set(proposal.ballots, n64hash, neuronId, v); + Map.set(proposal.ballots, thash, neuronId, v); proposalDelta := List.push(proposal.id, proposalDelta); }; case(#err(e)){ - logService.logError("err Failed to map vote for proposal: " # Nat64.toText(proposal.id) # "for neuron: " # Nat64.toText(neuronId) # " error " # e, ?"[getProposalDeltaAndUpdateState]"); + logService.logError("err Failed to map vote for proposal: " # Nat64.toText(proposal.id) # "for neuron: " # neuronId # " error " # e, ?"[getProposalDeltaAndUpdateState]"); }; } }; @@ -387,16 +509,16 @@ module { }; //TODO: what if more than 100 proposal have been created? intersect neuronBallots with proposals and check size. - switch(Map.get(proposal.ballots, n64hash, neuronId)){ + switch(Map.get(proposal.ballots, thash, neuronId)){ case(?vote) { if(vote == #Pending){ proposalDelta := List.push(proposal.id, proposalDelta); - Map.set(proposal.ballots, n64hash, neuronId, #Abstained); + Map.set(proposal.ballots, thash, neuronId, #Abstained); }; }; case(_){ proposalDelta := List.push(proposal.id, proposalDelta); - Map.set(proposal.ballots, n64hash, neuronId, #Abstained); + Map.set(proposal.ballots, thash, neuronId, #Abstained); }; }; }; @@ -407,8 +529,8 @@ module { if(not Map.has(neuron.topics, i32hash, proposal.topicId)){ continue l; }; - if(not Map.has(proposal.ballots, n64hash, neuronId)){ - Map.set(proposal.ballots, n64hash, neuronId, #Pending); + if(not Map.has(proposal.ballots, thash, neuronId)){ + Map.set(proposal.ballots, thash, neuronId, #Pending); proposalDelta := List.push(proposal.id, proposalDelta); }; }; @@ -424,7 +546,7 @@ module { continue l; }; - switch(Map.get(neuronTallies, n64hash, neuron)){ + switch(Map.get(neuronTallies, thash, neuron)){ case(?tallies){ var relatedProposals = List.nil(); for(tally in List.toIter(tallies)) { @@ -485,7 +607,7 @@ module { vote = #Pending; }; - switch(Map.get(proposal.ballots, n64hash, neuron)){ + switch(Map.get(proposal.ballots, thash, neuron)){ case(?voteRecord){ neuronVotes.add({neuronVote with vote = voteRecord}); if(voteRecord == #Yes) { @@ -576,7 +698,7 @@ module { return #err("governance ID not found"); }; - let #ok(neuron) = Result.fromOption(Map.get(neuronMap, n64hash, neuronId), "neuron not found") + let #ok(neuron) = Result.fromOption(Map.get(neuronMap, thash, neuronId), "neuron not found") else { return #err("neuron ID not found"); }; @@ -609,7 +731,12 @@ module { func getNeuronChunks(map : Map.Map) : List.List<[Nat64]> { var tmp = List.nil(); for(n in Map.keys(map)){ - tmp := List.push(n, tmp); + switch(textToNat64(n)){ + case (?success){ + tmp := List.push(success, tmp); + }; + case(_){}; + }; }; return List.chunks(20, tmp) |> @@ -618,6 +745,13 @@ module { }); }; + public func textToNat64(t : Text) : ?Nat64 { + switch (Nat.fromText(t)) { + case (null) { null }; + case (?n) { ?Nat64.fromNat(n) }; + }; + }; + }; }; \ No newline at end of file diff --git a/src/proposal_tracker_backend/Tally/TallyTypes.mo b/src/proposal_tracker_backend/Tally/TallyTypes.mo index 5c2a0be..95aabe6 100644 --- a/src/proposal_tracker_backend/Tally/TallyTypes.mo +++ b/src/proposal_tracker_backend/Tally/TallyTypes.mo @@ -23,9 +23,10 @@ module { }; public type GovernanceId = Text; - public type NeuronId = Nat64; + public type NeuronId = Text; public type TallyId = Text; public type ProposalId = Nat64; + public type TopicId = Int32; public type Vote = { #Yes; @@ -56,16 +57,16 @@ public type Vote = { public type TallyInfo = { tallyId : TallyId; alias : ?Text; - topics : [Int32]; + topics : [TopicId]; neurons : [NeuronId]; }; public type AddTallyArgs = { governanceId : Text; alias : ?Text; - topics : [Int32]; + topics : [TopicId]; neurons : [NeuronId]; - subscriber : Principal; + subscriber : ?Principal; }; public type Subscriber = actor { diff --git a/src/proposal_tracker_backend/main.mo b/src/proposal_tracker_backend/main.mo index 2943a77..b280bcc 100644 --- a/src/proposal_tracker_backend/main.mo +++ b/src/proposal_tracker_backend/main.mo @@ -7,7 +7,8 @@ import Time "mo:base/Time"; import Array "mo:base/Array"; import Result "mo:base/Result"; import Timer "mo:base/Timer"; -import G "./External_Canisters/NNS/NNSTypes"; +import NNSTypes "./External_Canisters/NNS/NNSTypes"; +import G "./guards"; import GS "./Governance/GovernanceService"; import FakeGovernance "./Governance/FakeGovernanceService"; import PT "./Proposal/ProposalTypes"; @@ -19,21 +20,24 @@ import Nat "mo:base/Nat"; import Debug "mo:base/Debug"; import Buffer "mo:base/Buffer"; import Principal "mo:base/Principal"; +import List "mo:base/List"; import LogService "./Log/LogService"; import LT "./Log/LogTypes"; import TallyService "./Tally/TallyService"; import TallyTypes "./Tally/TallyTypes"; -actor class ProposalTrackerBackend() = { +shared ({ caller }) actor class ProposalTrackerBackend() = { stable let logs = LogService.initLogModel(); + stable var custodians = List.make(caller); + let logService = LogService.LogServiceImpl(logs, 100, true); stable let trackerData = TR.init(); let trackerRepository = TR.TrackerRepository(trackerData, logService); //TEST ONLY let fakeGovernanceService = FakeGovernance.FakeGovernanceService(logService); let governanceService = GS.GovernanceService(); - let trackerService = TS.TrackerService(trackerRepository, fakeGovernanceService, logService, { + let trackerService = TS.TrackerService(trackerRepository, governanceService, logService, { cleanupStrategy = #DeleteAfterTime(#Days(7)); }); @@ -48,14 +52,17 @@ actor class ProposalTrackerBackend() = { } }; - public func addTally(args : TallyService.AddTallyArgs) : async Result.Result{ + public shared ({ caller }) func addTally(args : TallyService.AddTallyArgs) : async Result.Result{ + if (not G.isCustodian(caller, custodians)) { + return #err("Not authorized"); + }; await* tallyService.addTally(args) }; - public func getTally(tallyId : TallyTypes.TallyId) : async Result.Result { + public shared ({ caller }) func getTally(tallyId : TallyTypes.TallyId) : async Result.Result { switch(tallyService.getTally(tallyId)){ case(?t){ - let neuronBuffer = Buffer.Buffer(0); + let neuronBuffer = Buffer.Buffer(0); let topicBufer = Buffer.Buffer(0); for(topic in Map.keys(t.topics)){ topicBufer.add(topic); @@ -78,82 +85,90 @@ actor class ProposalTrackerBackend() = { } }; + public func deleteTally(tallyId : TallyTypes.TallyId) : async Result.Result<(), Text> { + if (not G.isCustodian(caller, custodians)) { + return #err("Not authorized"); + }; + + tallyService.deleteTally(tallyId) + }; + // TEST ENDPOINTS - public func testApproveProposal() : async (){ - let proposalId = fakeGovernanceService.addProposal(13, #Open); - let neurons = Buffer.Buffer(10); - neurons.add(fakeGovernanceService.addNeuron()); - neurons.add(fakeGovernanceService.addNeuron()); - neurons.add(fakeGovernanceService.addNeuron()); - neurons.add(fakeGovernanceService.addNeuron()); + // public func testApproveProposal() : async (){ + // let proposalId = fakeGovernanceService.addProposal(13, #Open); + // let neurons = Buffer.Buffer(10); + // neurons.add(Nat64.toText(fakeGovernanceService.addNeuron())); + // neurons.add(Nat64.toText(fakeGovernanceService.addNeuron())); + // neurons.add(Nat64.toText(fakeGovernanceService.addNeuron())); + // neurons.add(Nat64.toText(fakeGovernanceService.addNeuron())); - ignore await* tallyService.addTally({ - governanceId = "7g2oq-raaaa-aaaap-qb7sq-cai"; - alias = ?"Test Tally"; - topics = [13]; - neurons = Buffer.toArray(neurons); - subscriber = Principal.fromText("7g2oq-raaaa-aaaap-qb7sq-cai"); - }); + // ignore await* tallyService.addTally({ + // governanceId = "7g2oq-raaaa-aaaap-qb7sq-cai"; + // alias = ?"Test Tally"; + // topics = [13]; + // neurons = Buffer.toArray(neurons); + // subscriber = Principal.fromText("7g2oq-raaaa-aaaap-qb7sq-cai"); + // }); - await* tallyService.fetchProposalsAndUpdate(); + // await* tallyService.fetchProposalsAndUpdate(); - for(neuron in neurons.vals()){ - ignore fakeGovernanceService.voteWithNeuronOnProposal(neuron, proposalId, #Yes); - }; + // for(neuron in neurons.vals()){ + // ignore fakeGovernanceService.voteWithNeuronOnProposal(neuron, proposalId, #Yes); + // }; - await* tallyService.fetchProposalsAndUpdate(); + // await* tallyService.fetchProposalsAndUpdate(); - }; + // }; - public func testAddMockTally() : async Result.Result{ - let neurons = Buffer.Buffer(10); - neurons.add(fakeGovernanceService.addNeuron()); - neurons.add(fakeGovernanceService.addNeuron()); - neurons.add(fakeGovernanceService.addNeuron()); - neurons.add(fakeGovernanceService.addNeuron()); - - await* tallyService.addTally({ - governanceId = "7g2oq-raaaa-aaaap-qb7sq-cai"; - alias = ?"Test Tally"; - topics = [13]; - neurons = Buffer.toArray(neurons); - subscriber = Principal.fromText("7g2oq-raaaa-aaaap-qb7sq-cai"); - }); - }; + // public func testAddMockTally() : async Result.Result{ + // let neurons = Buffer.Buffer(10); + // neurons.add(fakeGovernanceService.addNeuron()); + // neurons.add(fakeGovernanceService.addNeuron()); + // neurons.add(fakeGovernanceService.addNeuron()); + // neurons.add(fakeGovernanceService.addNeuron()); + + // await* tallyService.addTally({ + // governanceId = "7g2oq-raaaa-aaaap-qb7sq-cai"; + // alias = ?"Test Tally"; + // topics = [13]; + // neurons = Buffer.toArray(neurons); + // subscriber = Principal.fromText("7g2oq-raaaa-aaaap-qb7sq-cai"); + // }); + // }; - public func testAddCodegovTally() : async Result.Result{ - let codegovNeurons : [TallyTypes.NeuronId] = [118900764328536345, 12979846186887799326, 2692859404205778191, 16405079610149095765, 16459595263909468577, 6542438359604605534, 14998600334911702241, 739503821726316206]; + // public func testAddCodegovTally() : async Result.Result{ + // let codegovNeurons : [TallyTypes.NeuronId] = [118900764328536345, 12979846186887799326, 2692859404205778191, 16405079610149095765, 16459595263909468577, 6542438359604605534, 14998600334911702241, 739503821726316206]; - for(neuron in codegovNeurons.vals()){ - ignore fakeGovernanceService.addNeuronWithId(neuron); - }; + // for(neuron in codegovNeurons.vals()){ + // ignore fakeGovernanceService.addNeuronWithId(neuron); + // }; - await* tallyService.addTally({ - governanceId = "rrkah-fqaaa-aaaaa-aaaaq-cai"; - alias = ?"Codegov"; - topics = [1,2,3,4,5,6,7,8,9,10,11,12,13]; - neurons = codegovNeurons; - subscriber = Principal.fromText("7g2oq-raaaa-aaaap-qb7sq-cai"); - }); - }; + // await* tallyService.addTally({ + // governanceId = "rrkah-fqaaa-aaaaa-aaaaq-cai"; + // alias = ?"Codegov"; + // topics = [1,2,3,4,5,6,7,8,9,10,11,12,13]; + // neurons = codegovNeurons; + // subscriber = Principal.fromText("7g2oq-raaaa-aaaap-qb7sq-cai"); + // }); + // }; - public func testVoteWithTallyOnProposal(tallyId : Text, proposalId : Nat64, vote : {#No; #Unspecified; #Yes}) : async Result.Result<(), Text>{ - let t = tallyService.getTally(tallyId); - switch(t){ - case(?tally){ - for(neuronId in Map.keys(tally.neurons)){ - ignore fakeGovernanceService.voteWithNeuronOnProposal(neuronId, proposalId, vote); - }; - #ok() - }; - case(_){ - #err("Tally not found") - }; - }; - }; + // public func testVoteWithTallyOnProposal(tallyId : Text, proposalId : Nat64, vote : {#No; #Unspecified; #Yes}) : async Result.Result<(), Text>{ + // let t = tallyService.getTally(tallyId); + // switch(t){ + // case(?tally){ + // for(neuronId in Map.keys(tally.neurons)){ + // ignore fakeGovernanceService.voteWithNeuronOnProposal(neuronId, proposalId, vote); + // }; + // #ok() + // }; + // case(_){ + // #err("Tally not found") + // }; + // }; + // }; public func testRunUpdate() : async (){ await* tallyService.fetchProposalsAndUpdate() @@ -178,20 +193,20 @@ actor class ProposalTrackerBackend() = { }; }; - public func testGetPendingProposals() : async Result.Result<[G.ProposalInfo], Text>{ + public func testGetPendingProposals() : async Result.Result<[NNSTypes.ProposalInfo], Text>{ await* fakeGovernanceService.getPendingProposals("asa"); }; - public func getNeuronWithId(id : TallyTypes.NeuronId) : async Result.Result{ - switch(fakeGovernanceService.getNeuronWithId(id)){ - case(?neuron){ - #ok(neuron.0) - }; - case(_){ - #err("Neuron not found") - }; - }; - }; + // public func getNeuronWithId(id : TallyTypes.NeuronId) : async Result.Result{ + // switch(fakeGovernanceService.getNeuronWithId(id)){ + // case(?neuron){ + // #ok(neuron.0) + // }; + // case(_){ + // #err("Neuron not found") + // }; + // }; + // }; //// TRACKER SERVICE TESTING ENDPOINTS public func getProposals(canisterId: Text, after : ?PT.ProposalId, topics : TT.TopicStrategy) : async Result.Result { @@ -239,6 +254,23 @@ actor class ProposalTrackerBackend() = { // await* trackerService.addGovernance("rrkah-fqaaa-aaaaa-aaaaq-cai", #All); // }; + ////////////////////////// + ////////////////// ADMIN + ////////////////////////// + public shared ({ caller }) func addCustodian(new_custodian : Principal) : async Result.Result { + if (not G.isCustodian(caller, custodians)) { + return #err("Not authorized"); + }; + + custodians := List.push(new_custodian, custodians); + + return #ok("Custodian Added"); + }; + + public shared ({ caller }) func getCustodians() : async List.List { + custodians; + }; + ////////////////////////// ////////////////// LOGS ////////////////////////// From c784eda648940620da14e29ea946249359ebc912 Mon Sep 17 00:00:00 2001 From: Zane Date: Sun, 17 Nov 2024 18:41:53 +0100 Subject: [PATCH 06/11] update tally --- .../Tally/TallyService.mo | 182 +++++++++++++++--- .../Tracker/TrackerService.mo | 4 +- 2 files changed, 160 insertions(+), 26 deletions(-) diff --git a/src/proposal_tracker_backend/Tally/TallyService.mo b/src/proposal_tracker_backend/Tally/TallyService.mo index 5034382..6e38052 100644 --- a/src/proposal_tracker_backend/Tally/TallyService.mo +++ b/src/proposal_tracker_backend/Tally/TallyService.mo @@ -48,7 +48,7 @@ module { type NeuronData = { id : NeuronId; - topics : Map.Map; + topics : Map.Map; }; type TallyData = { @@ -177,15 +177,23 @@ module { for(neuronId in args.neurons.vals()){ switch(Map.get(neuronMap, thash, neuronId)){ case(?neuron) { - for(topic in Map.keys(topicSet)){ - Map.set(neuron.topics, i32hash, topic, ()); + for(topic in args.topics.vals()){ + switch(Map.get(neuron.topics, i32hash, topic)){ + case(?topicData){ + Map.set(neuron.topics, i32hash, topic, topicData + 1); + }; + case(_){ + Map.set(neuron.topics, i32hash, topic, 1); + }; + }; }; - - //Map.set(neuronMap, thash, neuronId, {neuron with tallies = List.push(tallyId, neuron.tallies)}); }; case(_){ - //Map.set(neuronMap, thash, neuronId, {id = neuronId; topics = topicSet; tallies = List.push(tallyId, List.nil())}); - Map.set(neuronMap, thash, neuronId, {id = neuronId; topics = topicSet;}); + let topicMap = Map.new(); + for(topic in args.topics.vals()){ + Map.set(topicMap, i32hash, topic, 1); + }; + Map.set(neuronMap, thash, neuronId, {id = neuronId; topics = topicMap;}); }; }; @@ -217,6 +225,44 @@ module { }; }; + func updateNeuronTopics(governanceId : GovernanceId, neuronId : NeuronId, removedTopics : Map.Map, addedTopics : Map.Map) : () { + switch(Map.get(tallyModel.neurons, thash, governanceId)){ + case(?neuronMap){ + switch(Map.get(neuronMap, thash, neuronId)){ + case(?neuron) { + for(removedTopic in Map.keys(removedTopics)){ + switch(Map.get(neuron.topics, i32hash, removedTopic)){ + case(?topicData){ + let newCount : Nat = topicData - 1; + if(newCount == 0){ + Map.delete(neuron.topics, i32hash, removedTopic); + } else { + Map.set(neuron.topics, i32hash, removedTopic, newCount); + }; + }; + case(_){}; + }; + }; + + for(addedTopic in Map.keys(addedTopics)){ + switch(Map.get(neuron.topics, i32hash, addedTopic)){ + case(?topicData){ + let newCount : Nat = topicData + 1; + Map.set(neuron.topics, i32hash, addedTopic, newCount); + }; + case(_){ + Map.set(neuron.topics, i32hash, addedTopic, 1); + }; + }; + } + }; + case(_){}; + }; + }; + case(_){}; + }; + }; + public func deleteTally(tallyId : TallyId) : Result.Result<(), Text> { if(updateState == #Running){ return #err("Tallies are being updated, deleting could cause issues with global state"); @@ -240,6 +286,7 @@ module { deleteNeuron(tally.governanceCanister, neuronId); } else { Map.set(neurons, thash, neuronId, newList); + updateNeuronTopics(tally.governanceCanister, neuronId, tally.topics, Map.new()); }; }; case(_){}; @@ -261,6 +308,110 @@ module { #ok() }; + // func updateOrDeleteNeuron(neuronId : NeuronId) : () { + + // }; + + public func updateTally(tallyId : TallyId, newTally : {topics : [TopicId]; neurons : [NeuronId] }) : Result.Result<(), Text> { + if(updateState == #Running){ + return #err("Tallies are being updated, deleting could cause issues with global state"); + }; + + let #ok(tally) = Utils.optToRes(getTally(tallyId)) else {return #err("Tally not found")}; + let topicSet = Utils.arrayToSet(newTally.topics, i32hash); + let neuronSet = Utils.arrayToSet(newTally.neurons, thash); + + let removedTopics = Map.new(); + let addedTopics = Map.new(); + + for(topic in Map.keys(tally.topics)){ + if(not Map.has(topicSet, i32hash, topic)){ + Map.set(removedTopics, i32hash, topic, ()); + }; + }; + + for(topic in Map.keys(topicSet)){ + if(not Map.has(tally.topics, i32hash, topic)){ + Map.set(addedTopics, i32hash, topic, ()); + }; + }; + + //if the neuron is not in the new list it has to be removed from the tally neurons and the neuron itself has to be updated + for(neuronTally in Map.keys(tally.neurons)){ + if(not Map.has(neuronSet, thash, neuronTally)){ + switch(Map.get(tallyModel.talliesByNeuron, thash, tally.governanceCanister)){ + case(?neurons){ + for(neuronId in Map.keys(neurons)){ + switch(Map.get(neurons, thash, neuronId)){ + case(?tallies){ + let newList = List.filter(tallies, func(t : TallyData) : Bool {t.id != tallyId}); + //If no tallies depend on this neuron anymore it should be deleted. + if(List.size(newList) == 0){ + deleteNeuron(tally.governanceCanister, neuronId); + } else { + Map.set(neurons, thash, neuronId, newList); + updateNeuronTopics(tally.governanceCanister, neuronId, tally.topics, Map.new()); + }; + }; + case(_){}; + }; + }; + }; + case(_){}; + }; + }; + }; + + //add new neurons to tally or update them if there are new topics + for(neuronId in newTally.neurons.vals()){ + if(Map.has(tally.neurons, thash, neuronId)){ + //neuron might have to be updated + updateNeuronTopics(tally.governanceCanister, neuronId, removedTopics, addedTopics); + } else { + //neuron is new, add it + let neuronMap = Utils.getElseCreate(tallyModel.neurons, thash, tally.governanceCanister , Map.new()); + let tallyByNeuronMap = Utils.getElseCreate(tallyModel.talliesByNeuron, thash, tally.governanceCanister, Map.new>()); + switch(Map.get(neuronMap, thash, neuronId)){ + case(?neuron) { + for(topic in newTally.topics.vals()){ + switch(Map.get(neuron.topics, i32hash, topic)){ + case(?topicData){ + Map.set(neuron.topics, i32hash, topic, topicData + 1); + }; + case(_){ + Map.set(neuron.topics, i32hash, topic, 1); + }; + }; + }; + }; + case(_){ + let topicMap = Map.new(); + for(topic in newTally.topics.vals()){ + Map.set(topicMap, i32hash, topic, 1); + }; + Map.set(neuronMap, thash, neuronId, {id = neuronId; topics = topicMap;}); + }; + }; + + switch(Map.get(tallyByNeuronMap, thash, neuronId)){ + case(?tallies) { + Map.set(tallyByNeuronMap, thash, neuronId, List.push(tally, tallies)); + }; + case(_){ + var tallyList = List.nil(); + tallyList := List.push(tally, tallyList); + Map.set(tallyByNeuronMap, thash, neuronId, tallyList); + }; + }; + + }; + }; + + tally.topics := topicSet; + tally.neurons := neuronSet; + #ok() + }; + public func addSubscriber(subscriber : Principal, tallyId : TallyId) : Result.Result<(), Text> { let #ok(tally) = Utils.optToRes(getTally(tallyId)) else {return #err("Tally not found")}; @@ -284,23 +435,6 @@ module { } }; - public func updateTally(tallyId : TallyId, newTally : {topics : [TopicId]; neurons : [NeuronId] }) : Result.Result<(), Text> { - if(updateState == #Running){ - return #err("Tallies are being updated, deleting could cause issues with global state"); - }; - - let #ok(tally) = Utils.optToRes(getTally(tallyId)) else {return #err("Tally not found")}; - let topicSet = Utils.arrayToSet(newTally.topics, i32hash); - let neuronSet = Utils.arrayToSet(newTally.neurons, thash); - - tally.topics := topicSet; - tally.neurons := neuronSet; - - - - #ok() - }; - public func getSubscribersByTallyId(tallyId : TallyId) : [Principal]{ let buf = Buffer.Buffer(20); for((sub, tallies) in Map.entries(tallyModel.subscribers)){ diff --git a/src/proposal_tracker_backend/Tracker/TrackerService.mo b/src/proposal_tracker_backend/Tracker/TrackerService.mo index d7b34eb..3724407 100644 --- a/src/proposal_tracker_backend/Tracker/TrackerService.mo +++ b/src/proposal_tracker_backend/Tracker/TrackerService.mo @@ -132,11 +132,11 @@ module { case(#ok(validTopics)){ repository.addGovernance(governancePrincipal, metadata.name, metadata.description, filterValidTopics(validTopics, topicStrategy)); }; - case(#err(err)){ return #err("Error fetching valid topics:" #err); } + case(#err(err)){ return #err("[addGovernance] Error fetching valid topics:" #err); } }; }; - case(#err(err)){ return #err("Error fetching metadata:" #err); } + case(#err(err)){ return #err("[addGovernance] Error fetching metadata:" #err); } }; }; From 8f63fefd732c090933a08c29af4f86e8dc770464 Mon Sep 17 00:00:00 2001 From: Zane Date: Sun, 17 Nov 2024 19:35:41 +0100 Subject: [PATCH 07/11] fix topic ids --- .../External_Canisters/NNS/NNSMappings.mo | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/proposal_tracker_backend/External_Canisters/NNS/NNSMappings.mo b/src/proposal_tracker_backend/External_Canisters/NNS/NNSMappings.mo index 8ada81f..133bf34 100644 --- a/src/proposal_tracker_backend/External_Canisters/NNS/NNSMappings.mo +++ b/src/proposal_tracker_backend/External_Canisters/NNS/NNSMappings.mo @@ -78,23 +78,23 @@ module { // }; public let NNSTopics : [{id : Nat64; name : Text;description : ?Text;}] = [ - {id : Nat64 = 0; description = ?"Unspecified"; name = "Unspecified"}, - {id : Nat64 = 1; description = ?"Neuron Management"; name = "ManageNeuron"}, - {id : Nat64 = 2; description = ?"Exchange Rate"; name = "ExchangeRate"}, - {id : Nat64 = 3; description = ?"Network Economics"; name = "NetworkEconomics"}, - {id : Nat64 = 4; description = ?"Governance"; name = "Governance"}, - {id : Nat64 = 5; description = ?"Node Admin"; name = "NodeAdmin"}, - {id : Nat64 = 6; description = ?"Participant Management"; name = "ParticipantManagement"}, - {id : Nat64 = 7; description = ?"Subnet Management"; name = "SubnetManagement"}, - {id : Nat64 = 8; description = ?"System Canister Management"; name = "NetworkCanisterManagement"}, - {id : Nat64 = 9; description = ?"KYC"; name = "Kyc"}, - {id : Nat64 = 10; description = ?"Node Provider Rewards"; name = "NodeProviderRewards"}, - {id : Nat64 = 11; description = ?"SNS Decentralization Swap"; name = "SnsDecentralizationSale"}, - {id : Nat64 = 12; description = ?"IC OS Version Election"; name = "ReplicaVersionManagement"}, - {id : Nat64 = 13; description = ?"IC OS Version Deployment"; name = "SubnetReplicaVersionManagement"}, - {id : Nat64 = 14; description = ?"SNS & Neurons' Fund"; name = "SnsAndCommunityFund"}, - {id : Nat64 = 15; description = ?"API Boundary Node Management"; name = "ApiBoundaryNodeManagement"}, - {id : Nat64 = 16; description = ?"Subnet Rental"; name = "SubnetRental"} + {id : Nat64 = 1; description = ?"Unspecified"; name = "Unspecified"}, + {id : Nat64 = 2; description = ?"Neuron Management"; name = "ManageNeuron"}, + {id : Nat64 = 3; description = ?"Exchange Rate"; name = "ExchangeRate"}, + {id : Nat64 = 4; description = ?"Network Economics"; name = "NetworkEconomics"}, + {id : Nat64 = 5; description = ?"Governance"; name = "Governance"}, + {id : Nat64 = 6; description = ?"Node Admin"; name = "NodeAdmin"}, + {id : Nat64 = 7; description = ?"Participant Management"; name = "ParticipantManagement"}, + {id : Nat64 = 8; description = ?"Subnet Management"; name = "SubnetManagement"}, + {id : Nat64 = 9; description = ?"System Canister Management"; name = "NetworkCanisterManagement"}, + {id : Nat64 = 10; description = ?"KYC"; name = "Kyc"}, + {id : Nat64 = 11; description = ?"Node Provider Rewards"; name = "NodeProviderRewards"}, + {id : Nat64 = 12; description = ?"SNS Decentralization Swap"; name = "SnsDecentralizationSale"}, + {id : Nat64 = 13; description = ?"IC OS Version Election"; name = "ReplicaVersionManagement"}, + {id : Nat64 = 14; description = ?"IC OS Version Deployment"; name = "SubnetReplicaVersionManagement"}, + {id : Nat64 = 15; description = ?"SNS & Neurons' Fund"; name = "SnsAndCommunityFund"}, + {id : Nat64 = 16; description = ?"API Boundary Node Management"; name = "ApiBoundaryNodeManagement"}, + {id : Nat64 = 17; description = ?"Subnet Rental"; name = "SubnetRental"} ]; public type NNSVote = { #Unspecified; //0 From 130f13e8538fbbc1e2d7ebb0c9bfb6f6a480b738 Mon Sep 17 00:00:00 2001 From: Zane Date: Sun, 17 Nov 2024 19:36:03 +0100 Subject: [PATCH 08/11] fixed timer and save tickrate --- .../Tally/TallyService.mo | 27 +++++----- src/proposal_tracker_backend/main.mo | 51 +++++++++++++++++-- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/proposal_tracker_backend/Tally/TallyService.mo b/src/proposal_tracker_backend/Tally/TallyService.mo index 6e38052..49c5f6f 100644 --- a/src/proposal_tracker_backend/Tally/TallyService.mo +++ b/src/proposal_tracker_backend/Tally/TallyService.mo @@ -84,6 +84,7 @@ module { var lastId : Nat; var timerId :?Nat; + var tickrateInSeconds : ?Nat; }; public func initTallyModel() : TallyModel { @@ -99,6 +100,7 @@ module { var lastId = 0; var timerId = null; + var tickrateInSeconds = null; }; }; @@ -109,12 +111,14 @@ module { public func initTimer(_tickrateInSeconds : ?Nat) : async Result.Result<(), Text> { let tickrate : Nat = Option.get(_tickrateInSeconds, 5 * 60); // 5 minutes + tallyModel.tickrateInSeconds := ?tickrate; switch(tallyModel.timerId){ case(?t){ return #err("Timer already created")}; case(_){}; }; tallyModel.timerId := ?Timer.recurringTimer(#seconds(tickrate), func() : async () { + logService.logInfo("Running timer", null); await* fetchProposalsAndUpdate() }); @@ -134,15 +138,8 @@ module { } }; - public func init() : async Result.Result<(), Text> { - await* trackerService.initTimer(?300, func(governanceId : Text, new : [PT.ProposalAPI], updated : [PT.ProposalAPI]) : async* () { - // Debug.print("Tick"); - // Debug.print("new proposals: " # debug_show(new)); - // Debug.print("updated proposals: " # debug_show(updated)); - // Debug.print("governanceId: " # governanceId); - - // await* update(governanceId, new, updated); - }); + public func init(tickrateInSeconds : ?Nat) : async Result.Result<(), Text> { + await initTimer(tickrateInSeconds); }; public func addTally(args : AddTallyArgs) : async* Result.Result { @@ -335,7 +332,7 @@ module { Map.set(addedTopics, i32hash, topic, ()); }; }; - + //if the neuron is not in the new list it has to be removed from the tally neurons and the neuron itself has to be updated for(neuronTally in Map.keys(tally.neurons)){ if(not Map.has(neuronSet, thash, neuronTally)){ @@ -448,10 +445,14 @@ module { Buffer.toArray(buf); }; - public func getTalliesByPrincipal(principal : Principal) : Result.Result<[TallyData], Text> { + public func getTalliesByPrincipal(principal : Principal) : Result.Result<[{id : Text; alias : ?Text}], Text> { switch(Map.get(tallyModel.subscribers, phash, principal)){ case(?tallies){ - #ok(List.toArray(tallies)) + var buf = Buffer.Buffer<{id : Text; alias : ?Text}>(20); + for(tally in List.toIter(tallies)){ + buf.add({id = tally.id; alias = tally.alias;}); + }; + #ok(Buffer.toArray(buf)) }; case(_){ return #err("No tallies found") @@ -589,7 +590,7 @@ module { let #ok(proposal) = Result.fromOption(Map.get(proposals, n64hash, pId.id), "proposal not found") else { - logService.logError("proposal not found", ?"[getProposalDeltaAndUpdateState]"); + logService.logError("Proposal not found: " # Nat64.toText(pId.id), ?"[getProposalDeltaAndUpdateState]"); continue l; }; diff --git a/src/proposal_tracker_backend/main.mo b/src/proposal_tracker_backend/main.mo index b280bcc..56ec1e6 100644 --- a/src/proposal_tracker_backend/main.mo +++ b/src/proposal_tracker_backend/main.mo @@ -52,6 +52,14 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { } }; + public shared ({ caller }) func initTimer(tickrateInSeconds : ?Nat) : async Result.Result<(), Text>{ + if (not G.isCustodian(caller, custodians)) { + return #err("Not authorized"); + }; + + await tallyService.init(tickrateInSeconds); + }; + public shared ({ caller }) func addTally(args : TallyService.AddTallyArgs) : async Result.Result{ if (not G.isCustodian(caller, custodians)) { return #err("Not authorized"); @@ -85,14 +93,47 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { } }; - public func deleteTally(tallyId : TallyTypes.TallyId) : async Result.Result<(), Text> { + public shared ({ caller }) func deleteTally(tallyId : TallyTypes.TallyId) : async Result.Result<(), Text> { + if (not G.isCustodian(caller, custodians)) { + return #err("Not authorized"); + }; + + tallyService.deleteTally(tallyId) + }; + + public shared ({ caller }) func updateTally(tallyId : TallyTypes.TallyId, newTally : {topics : [TallyTypes.TopicId]; neurons : [TallyTypes.NeuronId] }) : async Result.Result<(), Text> { if (not G.isCustodian(caller, custodians)) { return #err("Not authorized"); }; - tallyService.deleteTally(tallyId) + tallyService.updateTally(tallyId, newTally) + }; + + public shared ({ caller }) func getSubscribersByTallyId(tallyId : TallyTypes.TallyId) : async [Principal] { + tallyService.getSubscribersByTallyId(tallyId) + }; + + public shared ({ caller }) func getTalliesByPrincipal(principal : Principal) : async Result.Result<[{id : Text; alias : ?Text}], Text> { + tallyService.getTalliesByPrincipal(principal) }; + public shared ({ caller }) func addSubscriber(subscriber : Principal, tallyId : TallyTypes.TallyId) : async Result.Result<(), Text> { + if (not G.isCustodian(caller, custodians)) { + return #err("Not authorized"); + }; + + tallyService.addSubscriber(subscriber, tallyId) + }; + + public shared ({ caller }) func deleteSubscriber(subscriber : Principal, tallyId : TallyTypes.TallyId) : async Result.Result<(), Text>{ + if (not G.isCustodian(caller, custodians)) { + return #err("Not authorized"); + }; + + tallyService.deleteSubscriber(subscriber, tallyId) + }; + + // TEST ENDPOINTS // public func testApproveProposal() : async (){ @@ -182,7 +223,7 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { await* tallyService.fetchProposalsAndUpdate(); }; - public func testAddPendingProposal(id : ?Nat64) : async Nat64{ + public func testAddMockPendingProposal(id : ?Nat64) : async Nat64{ switch(id){ case(?unwrapId){ fakeGovernanceService.addProposalWithId(unwrapId, 13, #Open); @@ -193,7 +234,7 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { }; }; - public func testGetPendingProposals() : async Result.Result<[NNSTypes.ProposalInfo], Text>{ + public func testGetMockPendingProposals() : async Result.Result<[NNSTypes.ProposalInfo], Text>{ await* fakeGovernanceService.getPendingProposals("asa"); }; @@ -213,7 +254,7 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { trackerService.getProposals(canisterId, after, topics); }; - public func testGetProposal(id : Nat64) : async Bool{ + public func testGetMockProposal(id : Nat64) : async Bool{ switch(fakeGovernanceService.getProposalWithId(id)){ case(?e){ true From d94be9f229274be1ef0ce8d8b671e81f3f8bbf74 Mon Sep 17 00:00:00 2001 From: Zane Date: Sun, 17 Nov 2024 21:57:29 +0100 Subject: [PATCH 09/11] expose timer related methods --- src/proposal_tracker_backend/main.mo | 68 ++++++++++++++++------------ 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/src/proposal_tracker_backend/main.mo b/src/proposal_tracker_backend/main.mo index 56ec1e6..7f8702c 100644 --- a/src/proposal_tracker_backend/main.mo +++ b/src/proposal_tracker_backend/main.mo @@ -31,7 +31,7 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { stable let logs = LogService.initLogModel(); stable var custodians = List.make(caller); - let logService = LogService.LogServiceImpl(logs, 100, true); + let logService = LogService.LogServiceImpl(logs, 200, true); stable let trackerData = TR.init(); let trackerRepository = TR.TrackerRepository(trackerData, logService); //TEST ONLY @@ -46,7 +46,8 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { system func postupgrade() { if(Option.isSome(tallyModel.timerId)){ - tallyModel.timerId := ?Timer.recurringTimer(#seconds(5* 60), func() : async () { + tallyModel.timerId := ?Timer.recurringTimer(#seconds(Option.get(tallyModel.tickrateInSeconds, 5 * 60)), func() : async () { + logService.logInfo("Running timer", null); await* tallyService.fetchProposalsAndUpdate() }); } @@ -60,6 +61,17 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { await tallyService.init(tickrateInSeconds); }; + public shared ({ caller }) func cancelTimer() : async Result.Result<(), Text>{ + if (not G.isCustodian(caller, custodians)) { + return #err("Not authorized"); + }; + await tallyService.cancelTimer(); + }; + + public func getTimerTickrate() : async ?Nat { + tallyModel.tickrateInSeconds + }; + public shared ({ caller }) func addTally(args : TallyService.AddTallyArgs) : async Result.Result{ if (not G.isCustodian(caller, custodians)) { return #err("Not authorized"); @@ -215,28 +227,28 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { await* tallyService.fetchProposalsAndUpdate() }; - public func testTerminateProposal(proposalId : Nat64) : async Result.Result<(), Text>{ - fakeGovernanceService.terminateProposal(proposalId); - }; + // public func testTerminateProposal(proposalId : Nat64) : async Result.Result<(), Text>{ + // fakeGovernanceService.terminateProposal(proposalId); + // }; public func testFetchProposalsAndUpdate() : async (){ await* tallyService.fetchProposalsAndUpdate(); }; - public func testAddMockPendingProposal(id : ?Nat64) : async Nat64{ - switch(id){ - case(?unwrapId){ - fakeGovernanceService.addProposalWithId(unwrapId, 13, #Open); - }; - case(_){ - fakeGovernanceService.addProposal(13, #Open); - }; - }; - }; + // public func testAddMockPendingProposal(id : ?Nat64) : async Nat64{ + // switch(id){ + // case(?unwrapId){ + // fakeGovernanceService.addProposalWithId(unwrapId, 13, #Open); + // }; + // case(_){ + // fakeGovernanceService.addProposal(13, #Open); + // }; + // }; + // }; - public func testGetMockPendingProposals() : async Result.Result<[NNSTypes.ProposalInfo], Text>{ - await* fakeGovernanceService.getPendingProposals("asa"); - }; + // public func testGetMockPendingProposals() : async Result.Result<[NNSTypes.ProposalInfo], Text>{ + // await* fakeGovernanceService.getPendingProposals("asa"); + // }; // public func getNeuronWithId(id : TallyTypes.NeuronId) : async Result.Result{ // switch(fakeGovernanceService.getNeuronWithId(id)){ @@ -254,16 +266,16 @@ shared ({ caller }) actor class ProposalTrackerBackend() = { trackerService.getProposals(canisterId, after, topics); }; - public func testGetMockProposal(id : Nat64) : async Bool{ - switch(fakeGovernanceService.getProposalWithId(id)){ - case(?e){ - true - }; - case(_){ - false - }; - } - }; + // public func testGetMockProposal(id : Nat64) : async Bool{ + // switch(fakeGovernanceService.getProposalWithId(id)){ + // case(?e){ + // true + // }; + // case(_){ + // false + // }; + // } + // }; public func testSetLowestActiveId(canisterId: Text, id : ?Nat64) : async Result.Result<(), Text> { let tc = Map.get(trackerData.trackedCanisters, thash, canisterId); From 3a3a84c4aa81c07b025f1dfc5d91a24d8d55624e Mon Sep 17 00:00:00 2001 From: Zane Date: Sun, 17 Nov 2024 21:57:55 +0100 Subject: [PATCH 10/11] minor changes to tally service --- .../Tally/TallyService.mo | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/proposal_tracker_backend/Tally/TallyService.mo b/src/proposal_tracker_backend/Tally/TallyService.mo index 49c5f6f..3827444 100644 --- a/src/proposal_tracker_backend/Tally/TallyService.mo +++ b/src/proposal_tracker_backend/Tally/TallyService.mo @@ -74,7 +74,7 @@ module { public type TallyModel = { neurons : Map.Map>; - tallies : Map.Map>; + //tallies : Map.Map>; proposals : Map.Map>; settledProposals : Map.Map>; subscribers : Map.Map>; @@ -90,7 +90,7 @@ module { public func initTallyModel() : TallyModel { { neurons = Map.new>(); - tallies = Map.new>(); + //tallies = Map.new>(); proposals = Map.new>(); settledProposals = Map.new>(); subscribers = Map.new>(); @@ -155,8 +155,8 @@ module { tallyModel.lastId := tallyModel.lastId + 1; let topicSet = Utils.arrayToSet(args.topics, i32hash); let tally : TallyData = {id = tallyId; alias = args.alias; governanceCanister = governanceId; var topics = topicSet; var neurons = Utils.arrayToSet(args.neurons, thash); ballots = Map.new()}; - let tallyMap = Utils.getElseCreate(tallyModel.tallies, thash, governanceId, Map.new()); - Map.set(tallyMap, thash, tallyId, tally); + // let tallyMap = Utils.getElseCreate(tallyModel.tallies, thash, governanceId, Map.new()); + // Map.set(tallyMap, thash, tallyId, tally); switch(args.subscriber){ case(?subscriber){ @@ -294,12 +294,12 @@ module { }; - switch(Map.get(tallyModel.tallies, thash, tally.governanceCanister)){ - case(?tallies){ - Map.delete(tallies, thash, tallyId); - }; - case(_){}; - }; + // switch(Map.get(tallyModel.tallies, thash, tally.governanceCanister)){ + // case(?tallies){ + // Map.delete(tallies, thash, tallyId); + // }; + // case(_){}; + // }; #ok() @@ -460,7 +460,7 @@ module { }; }; - //TODO: change + //TODO: change for SNS public func fetchProposalsAndUpdate() : async* (){ if(updateState == #Running){ logService.logWarn("Update already running", ?"[update]"); @@ -590,7 +590,7 @@ module { let #ok(proposal) = Result.fromOption(Map.get(proposals, n64hash, pId.id), "proposal not found") else { - logService.logError("Proposal not found: " # Nat64.toText(pId.id), ?"[getProposalDeltaAndUpdateState]"); + //logService.logError("Proposal not found: " # Nat64.toText(pId.id), ?"[getProposalDeltaAndUpdateState]"); continue l; }; @@ -692,6 +692,7 @@ module { continue l; }; if (Map.has(tally.topics, i32hash, proposal.topicId)) { + logService.logInfo("Tally ID: " # tally.id # " is affected cause proposal: " # Nat64.toText(proposal.id), ?"[processAffectedTallies]"); relatedProposals := List.push(proposal, relatedProposals); }; }; @@ -786,7 +787,7 @@ module { func chunkedSend(governanceId : Text, subscriberTallies : List.List, affectedTallies : Map.Map>, chunkSize : Nat) : async* () { let tallyChunk = Buffer.Buffer(chunkSize); for(tally in List.toIter(subscriberTallies)) { - if(Map.has(affectedTallies, thash, tally.id)){ + //if(Map.has(affectedTallies, thash, tally.id)){ switch(Map.get(affectedTallies, thash, tally.id)){ case(?proposals){ tallyChunk.add(processTally(tally, proposals)); @@ -797,7 +798,7 @@ module { }; case(_){}; } - }; + // }; }; if(tallyChunk.size() > 0) { await* notifySubscriber(governanceId, Buffer.toArray(tallyChunk)); From 513bea3cba2ecd58759d9489f65b152505cb2a7a Mon Sep 17 00:00:00 2001 From: Zane Date: Sun, 17 Nov 2024 23:08:17 +0100 Subject: [PATCH 11/11] fix affected tallies logic --- .../Tally/TallyService.mo | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/proposal_tracker_backend/Tally/TallyService.mo b/src/proposal_tracker_backend/Tally/TallyService.mo index 3827444..e381dca 100644 --- a/src/proposal_tracker_backend/Tally/TallyService.mo +++ b/src/proposal_tracker_backend/Tally/TallyService.mo @@ -683,16 +683,15 @@ module { switch(Map.get(neuronTallies, thash, neuron)){ case(?tallies){ - var relatedProposals = List.nil(); for(tally in List.toIter(tallies)) { - + var relatedProposals = List.nil(); for(proposalId in List.toIter(proposalList)) { let #ok(proposal) = getProposal(governanceId, proposalId) else { continue l; }; if (Map.has(tally.topics, i32hash, proposal.topicId)) { - logService.logInfo("Tally ID: " # tally.id # " is affected cause proposal: " # Nat64.toText(proposal.id), ?"[processAffectedTallies]"); + //logService.logInfo("Tally ID: " # tally.id # " is affected cause proposal: " # Nat64.toText(proposal.id), ?"[processAffectedTallies]"); relatedProposals := List.push(proposal, relatedProposals); }; }; @@ -704,6 +703,10 @@ module { case(_){}; }; }; + + // for((key, value) in Map.entries(affectedTallies)){ + // logService.logInfo("Proposals affected by tallyid: " # key # " n times:" # Nat.toText(List.size(value)), null); + // }; affectedTallies }; @@ -784,15 +787,16 @@ module { }; }; - func chunkedSend(governanceId : Text, subscriberTallies : List.List, affectedTallies : Map.Map>, chunkSize : Nat) : async* () { + func chunkedSend(subId : Text, subscriberTallies : List.List, affectedTallies : Map.Map>, chunkSize : Nat) : async* () { let tallyChunk = Buffer.Buffer(chunkSize); for(tally in List.toIter(subscriberTallies)) { //if(Map.has(affectedTallies, thash, tally.id)){ switch(Map.get(affectedTallies, thash, tally.id)){ case(?proposals){ + //logService.logInfo("Proposals affected by tallyid: " # tally.id # Nat.toText(List.size(proposals)), null); tallyChunk.add(processTally(tally, proposals)); if(tallyChunk.size() >= chunkSize) { - await* notifySubscriber(governanceId, Buffer.toArray(tallyChunk)); + await* notifySubscriber(subId, Buffer.toArray(tallyChunk)); tallyChunk.clear(); } }; @@ -801,12 +805,13 @@ module { // }; }; if(tallyChunk.size() > 0) { - await* notifySubscriber(governanceId, Buffer.toArray(tallyChunk)); + await* notifySubscriber(subId, Buffer.toArray(tallyChunk)); }; }; - func notifySubscriber(governanceId : Text, tallies : [TallyTypes.TallyFeed]) : async* () { - let sub : TallyTypes.Subscriber = actor (governanceId); + public func notifySubscriber(subId : Text, tallies : [TallyTypes.TallyFeed]) : async* () { + logService.logInfo("Notifying subscriber", null); + let sub : TallyTypes.Subscriber = actor (subId); await sub.tallyUpdate(tallies); };