From 9eef2caa4ea4f8983145841ba5bc35926d567d3f Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 23 May 2022 20:50:56 +0200 Subject: [PATCH 1/7] Add events --- src/neo/SmartContract/Native/NeoToken.cs | 76 ++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/neo/SmartContract/Native/NeoToken.cs b/src/neo/SmartContract/Native/NeoToken.cs index 9000836908..a372c5dfaa 100644 --- a/src/neo/SmartContract/Native/NeoToken.cs +++ b/src/neo/SmartContract/Native/NeoToken.cs @@ -14,6 +14,7 @@ using Neo.IO; using Neo.Persistence; using Neo.SmartContract.Iterators; +using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; using System; @@ -56,6 +57,73 @@ public sealed class NeoToken : FungibleToken internal NeoToken() { this.TotalAmount = 100000000 * Factor; + + var events = new List(Manifest.Abi.Events) + { + new ContractEventDescriptor + { + Name = "CandidateRegistered", + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = "pubkey", + Type = ContractParameterType.PublicKey + }, + new ContractParameterDefinition() + { + Name = "votes", + Type = ContractParameterType.Integer + } + } + }, + new ContractEventDescriptor + { + Name = "CandidateUnregistered", + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = "pubkey", + Type = ContractParameterType.PublicKey + }, + new ContractParameterDefinition() + { + Name = "votes", + Type = ContractParameterType.Integer + } + } + }, + new ContractEventDescriptor + { + Name = "VoteCasted", + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = "account", + Type = ContractParameterType.Hash160 + }, + new ContractParameterDefinition() + { + Name = "voteTo", + Type = ContractParameterType.PublicKey + }, + new ContractParameterDefinition() + { + Name = "balance", + Type = ContractParameterType.Integer + }, + new ContractParameterDefinition() + { + Name = "votes", + Type = ContractParameterType.Integer + } + } + } + }; + + Manifest.Abi.Events = events.ToArray(); } public override BigInteger TotalSupply(DataCache snapshot) @@ -295,7 +363,10 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) StorageKey key = CreateStorageKey(Prefix_Candidate).Add(pubkey); StorageItem item = engine.Snapshot.GetAndChange(key, () => new StorageItem(new CandidateState())); CandidateState state = item.GetInteroperable(); + if (state.Registered) return true; state.Registered = true; + engine.SendNotification(Hash, "CandidateRegistered", + new VM.Types.Array(engine.ReferenceCounter) { pubkey.ToArray(), state.Votes }); return true; } @@ -308,8 +379,11 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) if (engine.Snapshot.TryGet(key) is null) return true; StorageItem item = engine.Snapshot.GetAndChange(key); CandidateState state = item.GetInteroperable(); + if (!state.Registered) return true; state.Registered = false; CheckCandidate(engine.Snapshot, pubkey, state); + engine.SendNotification(Hash, "CandidateUnregistered", + new VM.Types.Array(engine.ReferenceCounter) { pubkey.ToArray(), state.Votes }); return true; } @@ -350,6 +424,8 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, } if (gasDistribution is not null) await GAS.Mint(engine, gasDistribution.Account, gasDistribution.Amount, true); + engine.SendNotification(Hash, "VoteCasted", + new VM.Types.Array(engine.ReferenceCounter) { account.ToArray(), voteTo?.ToArray() ?? StackItem.Null, state_account.Balance, validator_new?.Votes ?? StackItem.Null }); return true; } From f040db14afae9d6c3dd169099a19315ad0390581 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 24 May 2022 15:41:09 +0200 Subject: [PATCH 2/7] Unify --- src/neo/SmartContract/Native/NeoToken.cs | 30 +++++++----------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/neo/SmartContract/Native/NeoToken.cs b/src/neo/SmartContract/Native/NeoToken.cs index a372c5dfaa..bde40812c9 100644 --- a/src/neo/SmartContract/Native/NeoToken.cs +++ b/src/neo/SmartContract/Native/NeoToken.cs @@ -62,7 +62,7 @@ internal NeoToken() { new ContractEventDescriptor { - Name = "CandidateRegistered", + Name = "CandidateStateChanged", Parameters = new ContractParameterDefinition[] { new ContractParameterDefinition() @@ -72,20 +72,8 @@ internal NeoToken() }, new ContractParameterDefinition() { - Name = "votes", - Type = ContractParameterType.Integer - } - } - }, - new ContractEventDescriptor - { - Name = "CandidateUnregistered", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "pubkey", - Type = ContractParameterType.PublicKey + Name = "registered", + Type = ContractParameterType.Boolean }, new ContractParameterDefinition() { @@ -96,7 +84,7 @@ internal NeoToken() }, new ContractEventDescriptor { - Name = "VoteCasted", + Name = "Vote", Parameters = new ContractParameterDefinition[] { new ContractParameterDefinition() @@ -365,8 +353,8 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) CandidateState state = item.GetInteroperable(); if (state.Registered) return true; state.Registered = true; - engine.SendNotification(Hash, "CandidateRegistered", - new VM.Types.Array(engine.ReferenceCounter) { pubkey.ToArray(), state.Votes }); + engine.SendNotification(Hash, "CandidateStateChanged", + new VM.Types.Array(engine.ReferenceCounter) { pubkey.ToArray(), true, state.Votes }); return true; } @@ -382,8 +370,8 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) if (!state.Registered) return true; state.Registered = false; CheckCandidate(engine.Snapshot, pubkey, state); - engine.SendNotification(Hash, "CandidateUnregistered", - new VM.Types.Array(engine.ReferenceCounter) { pubkey.ToArray(), state.Votes }); + engine.SendNotification(Hash, "CandidateStateChanged", + new VM.Types.Array(engine.ReferenceCounter) { pubkey.ToArray(), false, state.Votes }); return true; } @@ -424,7 +412,7 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, } if (gasDistribution is not null) await GAS.Mint(engine, gasDistribution.Account, gasDistribution.Amount, true); - engine.SendNotification(Hash, "VoteCasted", + engine.SendNotification(Hash, "Vote", new VM.Types.Array(engine.ReferenceCounter) { account.ToArray(), voteTo?.ToArray() ?? StackItem.Null, state_account.Balance, validator_new?.Votes ?? StackItem.Null }); return true; } From 703d704e6f9a67a74b4c81f22c68cc8fd7514535 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Tue, 24 May 2022 22:59:24 +0800 Subject: [PATCH 3/7] Distribute gas after notification --- src/neo/SmartContract/Native/NeoToken.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Native/NeoToken.cs b/src/neo/SmartContract/Native/NeoToken.cs index bde40812c9..86362e706f 100644 --- a/src/neo/SmartContract/Native/NeoToken.cs +++ b/src/neo/SmartContract/Native/NeoToken.cs @@ -410,10 +410,10 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, { validator_new.Votes += state_account.Balance; } - if (gasDistribution is not null) - await GAS.Mint(engine, gasDistribution.Account, gasDistribution.Amount, true); engine.SendNotification(Hash, "Vote", new VM.Types.Array(engine.ReferenceCounter) { account.ToArray(), voteTo?.ToArray() ?? StackItem.Null, state_account.Balance, validator_new?.Votes ?? StackItem.Null }); + if (gasDistribution is not null) + await GAS.Mint(engine, gasDistribution.Account, gasDistribution.Amount, true); return true; } From a80fa802ae1d99ecf37e304b8151aa968b0df25a Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 26 May 2022 10:34:17 +0200 Subject: [PATCH 4/7] Erik's feedback --- src/neo/SmartContract/Native/NeoToken.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/neo/SmartContract/Native/NeoToken.cs b/src/neo/SmartContract/Native/NeoToken.cs index 86362e706f..a1ec71fc5b 100644 --- a/src/neo/SmartContract/Native/NeoToken.cs +++ b/src/neo/SmartContract/Native/NeoToken.cs @@ -94,17 +94,17 @@ internal NeoToken() }, new ContractParameterDefinition() { - Name = "voteTo", + Name = "from", Type = ContractParameterType.PublicKey }, new ContractParameterDefinition() { - Name = "balance", - Type = ContractParameterType.Integer + Name = "to", + Type = ContractParameterType.PublicKey }, new ContractParameterDefinition() { - Name = "votes", + Name = "amount", Type = ContractParameterType.Integer } } @@ -405,13 +405,14 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, state_validator.Votes -= state_account.Balance; CheckCandidate(engine.Snapshot, state_account.VoteTo, state_validator); } + ECPoint from = state_account.VoteTo; state_account.VoteTo = voteTo; if (validator_new != null) { validator_new.Votes += state_account.Balance; } engine.SendNotification(Hash, "Vote", - new VM.Types.Array(engine.ReferenceCounter) { account.ToArray(), voteTo?.ToArray() ?? StackItem.Null, state_account.Balance, validator_new?.Votes ?? StackItem.Null }); + new VM.Types.Array(engine.ReferenceCounter) { account.ToArray(), from?.ToArray() ?? StackItem.Null, voteTo?.ToArray() ?? StackItem.Null, validator_new?.Votes ?? Integer.Zero }); if (gasDistribution is not null) await GAS.Mint(engine, gasDistribution.Account, gasDistribution.Amount, true); return true; From de0412e387eff82b5d4a77dec60b85fd4e62bf01 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 26 May 2022 10:36:12 +0200 Subject: [PATCH 5/7] Optimize without neo --- src/neo/SmartContract/Native/NeoToken.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/neo/SmartContract/Native/NeoToken.cs b/src/neo/SmartContract/Native/NeoToken.cs index a1ec71fc5b..3e10889125 100644 --- a/src/neo/SmartContract/Native/NeoToken.cs +++ b/src/neo/SmartContract/Native/NeoToken.cs @@ -381,6 +381,7 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, if (!engine.CheckWitnessInternal(account)) return false; NeoAccountState state_account = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Account).Add(account))?.GetInteroperable(); if (state_account is null) return false; + if (state_account.Balance == 0) return false; CandidateState validator_new = null; if (voteTo != null) { From 744a1d7c88ef21509143b73662309e2ab8b94aa1 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 26 May 2022 22:56:59 +0200 Subject: [PATCH 6/7] Update src/neo/SmartContract/Native/NeoToken.cs Co-authored-by: Erik Zhang --- src/neo/SmartContract/Native/NeoToken.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/SmartContract/Native/NeoToken.cs b/src/neo/SmartContract/Native/NeoToken.cs index 3e10889125..aaf6b27bd0 100644 --- a/src/neo/SmartContract/Native/NeoToken.cs +++ b/src/neo/SmartContract/Native/NeoToken.cs @@ -413,7 +413,7 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, validator_new.Votes += state_account.Balance; } engine.SendNotification(Hash, "Vote", - new VM.Types.Array(engine.ReferenceCounter) { account.ToArray(), from?.ToArray() ?? StackItem.Null, voteTo?.ToArray() ?? StackItem.Null, validator_new?.Votes ?? Integer.Zero }); + new VM.Types.Array(engine.ReferenceCounter) { account.ToArray(), from?.ToArray() ?? StackItem.Null, voteTo?.ToArray() ?? StackItem.Null, state_account.Balance }); if (gasDistribution is not null) await GAS.Mint(engine, gasDistribution.Account, gasDistribution.Amount, true); return true; From 08c8605b470991464b6e415a247659ca8588a499 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 27 May 2022 06:44:03 +0800 Subject: [PATCH 7/7] Fix UT --- tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index 18638a45e2..5064b52689 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -873,6 +873,7 @@ public void TestVote() snapshot.Delete(keyAccount); snapshot.GetAndChange(keyAccount, () => new StorageItem(new NeoAccountState { + Balance = 1, VoteTo = ECCurve.Secp256r1.G })); snapshot.Add(keyValidator, new StorageItem(new CandidateState()));