From 928d42e49288bc144dacb2b9ff3936d19c963c06 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 16:26:14 +0800 Subject: [PATCH 01/27] add incentive for neo holders --- .../SmartContract/Native/Tokens/NeoToken.cs | 156 +++++++++++++++--- .../Native/Tokens/UT_GasToken.cs | 40 +++-- .../Native/Tokens/UT_NeoToken.cs | 43 ++++- 3 files changed, 198 insertions(+), 41 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index aa8ea6da75..33ab71360b 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -27,6 +27,11 @@ public sealed class NeoToken : Nep5Token private const byte Prefix_Candidate = 33; private const byte Prefix_NextValidators = 14; + private const byte Prefix_GasPerBlock = 29; + private const byte Prefix_RewardRatio = 15; + private const byte Prefix_HolderRewardPerBlock = 27; + + internal NeoToken() { this.TotalAmount = 100000000 * Factor; @@ -50,45 +55,65 @@ protected override void OnBalanceChanging(ApplicationEngine engine, UInt160 acco private void DistributeGas(ApplicationEngine engine, UInt160 account, NeoAccountState state) { - BigInteger gas = CalculateBonus(state.Balance, state.BalanceHeight, engine.Snapshot.PersistingBlock.Index); + BigInteger gas = CalculateBonus(engine.Snapshot, state.Balance, state.BalanceHeight, engine.Snapshot.PersistingBlock.Index); state.BalanceHeight = engine.Snapshot.PersistingBlock.Index; GAS.Mint(engine, account, gas); } - private BigInteger CalculateBonus(BigInteger value, uint start, uint end) + private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint start, uint end) { if (value.IsZero || start >= end) return BigInteger.Zero; if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value)); - BigInteger amount = BigInteger.Zero; - uint ustart = start / Blockchain.DecrementInterval; - if (ustart < Blockchain.GenerationAmount.Length) + var endRewardItem = snapshot.Storages.TryGet(CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue - end - 1)); + var startRewardItem = snapshot.Storages.TryGet(CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue - start - 1)); + BigInteger startReward = startRewardItem is null ? 0 : new BigInteger(startRewardItem.Value); + BigInteger endReward = endRewardItem is null ? 0 : new BigInteger(endRewardItem.Value); + return value * (endReward - startReward) / TotalAmount; + } + + private void DistributeGasForCommittee(ApplicationEngine engine) + { + var gasPerBlock = GetGasPerBlock(engine.Snapshot); + (ECPoint, BigInteger)[] committeeVotes = GetCommitteeVotes(engine.Snapshot); + RewardRatio rewardRatio = GetRewardRatio(engine.Snapshot); + BigInteger holderRewardPerBlock = gasPerBlock * rewardRatio.NeoHolder / 100; // The final calculation should be divided by the total number of NEO + + // Keep track of incremental gains of neo holders + + var index = engine.Snapshot.PersistingBlock.Index; + var holderRewards = holderRewardPerBlock; + var holderRewardKey = CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue - index - 1); + var holderBorderKey = CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue); + var enumerator = engine.Snapshot.Storages.FindRange(holderRewardKey, holderBorderKey).GetEnumerator(); + if (enumerator.MoveNext()) + holderRewards += new BigInteger(enumerator.Current.Value.Value); + engine.Snapshot.Storages.Add(holderRewardKey, new StorageItem() { Value = holderRewards.ToByteArray() }); + + + for (var i = 0; i < committeeVotes.Length; i++) { - uint istart = start % Blockchain.DecrementInterval; - uint uend = end / Blockchain.DecrementInterval; - uint iend = end % Blockchain.DecrementInterval; - if (uend >= Blockchain.GenerationAmount.Length) - { - uend = (uint)Blockchain.GenerationAmount.Length; - iend = 0; - } - if (iend == 0) - { - uend--; - iend = Blockchain.DecrementInterval; - } - while (ustart < uend) - { - amount += (Blockchain.DecrementInterval - istart) * Blockchain.GenerationAmount[ustart]; - ustart++; - istart = 0; - } - amount += (iend - istart) * Blockchain.GenerationAmount[ustart]; + // Mint the reward for committee by each block + + UInt160 committeeAddr = Contract.CreateSignatureContract(committeeVotes[i].Item1).ScriptHash; + GAS.Mint(engine, committeeAddr, holderRewardPerBlock); } - return value * amount * GAS.Factor / TotalAmount; } internal override void Initialize(ApplicationEngine engine) { + // Initialize economic parameters + + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock), new StorageItem + { + Value = (5 * GAS.Factor).ToByteArray() + }); + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_RewardRatio), new StorageItem(new RewardRatio + { + NeoHolder = 10, + Committee = 5, + Voter = 85 + })); + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0])); Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), TotalAmount); } @@ -98,6 +123,41 @@ protected override void OnPersist(ApplicationEngine engine) base.OnPersist(engine); StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_NextValidators), () => new StorageItem()); storage.Value = GetValidators(engine.Snapshot).ToByteArray(); + DistributeGasForCommittee(engine); + } + + [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] + private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) + { + if (gasPerBlock < 0 || gasPerBlock > 8 * GAS.Factor) return false; + if (!CheckCommittees(engine)) return false; + StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)); + item.Value = gasPerBlock.ToByteArray(); + return true; + } + + [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] + private bool SetRewardRatio(ApplicationEngine engine, byte neoHoldersRewardRatio, byte committeesRewardRatio, byte votersRewardRatio) + { + if (checked(neoHoldersRewardRatio + committeesRewardRatio + votersRewardRatio) != 100) return false; + if (!CheckCommittees(engine)) return false; + RewardRatio rewardRatio = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_RewardRatio), () => new StorageItem(new RewardRatio())).GetInteroperable(); + rewardRatio.NeoHolder = neoHoldersRewardRatio; + rewardRatio.Committee = committeesRewardRatio; + rewardRatio.Voter = votersRewardRatio; + return true; + } + + [ContractMethod(1_00000000, CallFlags.AllowStates)] + public BigInteger GetGasPerBlock(StoreView snapshot) + { + return new BigInteger(snapshot.Storages.TryGet(CreateStorageKey(Prefix_GasPerBlock)).Value); + } + + [ContractMethod(1_00000000, CallFlags.AllowStates)] + internal RewardRatio GetRewardRatio(StoreView snapshot) + { + return snapshot.Storages.TryGet(CreateStorageKey(Prefix_RewardRatio)).GetInteroperable(); } [ContractMethod(0_03000000, CallFlags.AllowStates)] @@ -106,7 +166,7 @@ public BigInteger UnclaimedGas(StoreView snapshot, UInt160 account, uint end) StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_Account).Add(account)); if (storage is null) return BigInteger.Zero; NeoAccountState state = storage.GetInteroperable(); - return CalculateBonus(state.Balance, state.BalanceHeight, end); + return CalculateBonus(snapshot, state.Balance, state.BalanceHeight, end); } [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] @@ -204,6 +264,28 @@ public UInt160 GetCommitteeAddress(StoreView snapshot) return Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); } + public bool CheckCommittees(ApplicationEngine engine) + { + UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); + return engine.CheckWitnessInternal(committeeMultiSigAddr); + } + + private (ECPoint PublicKey, BigInteger Votes)[] GetCommitteeVotes(StoreView snapshot) + { + (ECPoint PublicKey, BigInteger Votes)[] committeeVotes = new (ECPoint PublicKey, BigInteger Votes)[ProtocolSettings.Default.CommitteeMembersCount]; + var i = 0; + foreach (var commiteePubKey in GetCommitteeMembers(snapshot)) + { + var item = snapshot.Storages.TryGet(CreateStorageKey(Prefix_Candidate).Add(commiteePubKey)); + if (item is null) + committeeVotes[i] = (commiteePubKey, BigInteger.Zero); + else + committeeVotes[i] = (commiteePubKey, item.GetInteroperable().Votes); + i++; + } + return committeeVotes; + } + private IEnumerable GetCommitteeMembers(StoreView snapshot) { decimal votersCount = (decimal)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_VotersCount)]; @@ -263,5 +345,25 @@ public StackItem ToStackItem(ReferenceCounter referenceCounter) return new Struct(referenceCounter) { Registered, Votes }; } } + + internal class RewardRatio : IInteroperable + { + public int NeoHolder; + public int Committee; + public int Voter; + + public void FromStackItem(StackItem stackItem) + { + VM.Types.Array array = (VM.Types.Array)stackItem; + NeoHolder = (int)array[0].GetInteger(); + Committee = (int)array[1].GetInteger(); + Voter = (int)array[2].GetInteger(); + } + + public StackItem ToStackItem(ReferenceCounter referenceCounter) + { + return new VM.Types.Array() { new Integer(NeoHolder), new Integer(Committee), new Integer(Voter) }; + } + } } } diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 380bdb65a6..9f26ecc79b 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -48,8 +48,11 @@ public void Check_BalanceOfTransferAndBurn() // Check unclaim + snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 1000 - 1), new StorageItem() { Value = new BigInteger(1000 * 100000000L).ToByteArray() }); + snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); + var unclaim = UT_NeoToken.Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(600000000000)); + unclaim.Value.Should().Be(new BigInteger(1000 * 100000000L)); unclaim.State.Should().BeTrue(); // Transfer @@ -58,7 +61,7 @@ public void Check_BalanceOfTransferAndBurn() NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(100000000); NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(0); - NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(30006000_00000000); + NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(30001000_00000000); NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(0); // Check unclaim @@ -68,21 +71,21 @@ public void Check_BalanceOfTransferAndBurn() unclaim.State.Should().BeTrue(); supply = NativeContract.GAS.TotalSupply(snapshot); - supply.Should().Be(30006000_00000000); + supply.Should().Be(30001000_00000000); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 3); // Gas + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 5); // Gas // Transfer keyCount = snapshot.Storages.GetChangeSet().Count(); - NativeContract.GAS.Transfer(snapshot, from, to, 30006000_00000000, false).Should().BeFalse(); // Not signed - NativeContract.GAS.Transfer(snapshot, from, to, 30006000_00000001, true).Should().BeFalse(); // More than balance - NativeContract.GAS.Transfer(snapshot, from, to, 30006000_00000000, true).Should().BeTrue(); // All balance + NativeContract.GAS.Transfer(snapshot, from, to, 30001000_00000000, false).Should().BeFalse(); // Not signed + NativeContract.GAS.Transfer(snapshot, from, to, 30001000_00000001, true).Should().BeFalse(); // More than balance + NativeContract.GAS.Transfer(snapshot, from, to, 30001000_00000000, true).Should().BeTrue(); // All balance // Balance of - NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30006000_00000000); + NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30001000_00000000); NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(0); snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 1); // All @@ -104,13 +107,13 @@ public void Check_BalanceOfTransferAndBurn() NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(1)); - NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30005999_99999999); + NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000099999999999); keyCount.Should().Be(snapshot.Storages.GetChangeSet().Count()); // Burn all - NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(30005999_99999999)); + NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000099999999999)); (keyCount - 1).Should().Be(snapshot.Storages.GetChangeSet().Count()); @@ -132,5 +135,22 @@ public void Check_BadScript() Assert.ThrowsException(() => NativeContract.GAS.Invoke(engine)); } + + internal static StorageKey CreateStorageKey(byte prefix, uint key) + { + return CreateStorageKey(prefix, BitConverter.GetBytes(key)); + } + + internal static StorageKey CreateStorageKey(byte prefix, byte[] key = null) + { + StorageKey storageKey = new StorageKey + { + Id = NativeContract.NEO.Id, + Key = new byte[sizeof(byte) + (key?.Length ?? 0)] + }; + storageKey.Key[0] = prefix; + key?.CopyTo(storageKey.Key.AsSpan(1)); + return storageKey; + } } } diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 75857ea9d3..3885c3d844 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -186,8 +186,11 @@ public void Check_UnclaimedGas() byte[] from = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); + snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 1000 - 1), new StorageItem() { Value = new BigInteger(1000 * 100000000L).ToByteArray() }); + snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); + var unclaim = Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(600000000000)); + unclaim.Value.Should().Be(new BigInteger(1000 * 100000000L)); unclaim.State.Should().BeTrue(); unclaim = Check_UnclaimedGas(snapshot, new byte[19]); @@ -338,8 +341,11 @@ public void Check_Transfer() // Check unclaim + snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 1000 - 1), new StorageItem() { Value = new BigInteger(1000 * 100000000L).ToByteArray() }); + snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); + var unclaim = Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(600000000000)); + unclaim.Value.Should().Be(new BigInteger(1000 * 100000000L)); unclaim.State.Should().BeTrue(); // Transfer @@ -355,7 +361,7 @@ public void Check_Transfer() unclaim.Value.Should().Be(new BigInteger(0)); unclaim.State.Should().BeTrue(); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + new balance + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 6); // Gas + new balance // Return balance @@ -416,6 +422,9 @@ public void TestCalculateBonus() { var snapshot = Blockchain.Singleton.GetSnapshot(); StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); + + // Fault: balance < 0 + snapshot.Storages.Add(key, new StorageItem(new NeoAccountState { Balance = -100 @@ -423,11 +432,27 @@ public void TestCalculateBonus() Action action = () => NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); action.Should().Throw(); snapshot.Storages.Delete(key); + + // Fault range: start >= end + + snapshot.Storages.GetAndChange(key, () => new StorageItem(new NeoAccountState + { + Balance = 100, + BalanceHeight = 100 + })); + action = () => NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + snapshot.Storages.Delete(key); + + // Normal 1) votee is non exist + snapshot.Storages.GetAndChange(key, () => new StorageItem(new NeoAccountState { Balance = 100 })); - NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 30 * Blockchain.DecrementInterval).Should().Be(new BigInteger(7000000000)); + snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 100 - 1), new StorageItem() { Value = new BigInteger(100 * 100000000L).ToByteArray() }); + snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); + NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 100).Should().Be(new BigInteger(100 * 100)); + snapshot.Storages.Delete(key); } [TestMethod] @@ -779,5 +804,15 @@ internal static (bool State, bool Result) Check_UnregisterCandidate(StoreView sn return (true, result.GetBoolean()); } + + internal static StorageKey CreateStorageKey(byte prefix, uint key) + { + return CreateStorageKey(prefix, BitConverter.GetBytes(key)); + } + + internal static StorageKey CreateStorageKey(byte prefix, ISerializable keyLeft, uint keyRight) + { + return CreateStorageKey(prefix, keyLeft.ToArray().Concat(BitConverter.GetBytes(keyRight)).ToArray()); + } } } From 98dd63c668c0400421d324d755e0afe98ce932dc Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 16:28:07 +0800 Subject: [PATCH 02/27] format --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 33ab71360b..d16248b50d 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -31,7 +31,6 @@ public sealed class NeoToken : Nep5Token private const byte Prefix_RewardRatio = 15; private const byte Prefix_HolderRewardPerBlock = 27; - internal NeoToken() { this.TotalAmount = 100000000 * Factor; From 24ce55cac8b43947e5c85ecbfb7878ed82aae9e7 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 16:36:29 +0800 Subject: [PATCH 03/27] rename --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index d16248b50d..e9dd8f9b3f 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -70,10 +70,9 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta return value * (endReward - startReward) / TotalAmount; } - private void DistributeGasForCommittee(ApplicationEngine engine) + private void RecordCumulativeGasByBlock(ApplicationEngine engine) { var gasPerBlock = GetGasPerBlock(engine.Snapshot); - (ECPoint, BigInteger)[] committeeVotes = GetCommitteeVotes(engine.Snapshot); RewardRatio rewardRatio = GetRewardRatio(engine.Snapshot); BigInteger holderRewardPerBlock = gasPerBlock * rewardRatio.NeoHolder / 100; // The final calculation should be divided by the total number of NEO @@ -87,15 +86,6 @@ private void DistributeGasForCommittee(ApplicationEngine engine) if (enumerator.MoveNext()) holderRewards += new BigInteger(enumerator.Current.Value.Value); engine.Snapshot.Storages.Add(holderRewardKey, new StorageItem() { Value = holderRewards.ToByteArray() }); - - - for (var i = 0; i < committeeVotes.Length; i++) - { - // Mint the reward for committee by each block - - UInt160 committeeAddr = Contract.CreateSignatureContract(committeeVotes[i].Item1).ScriptHash; - GAS.Mint(engine, committeeAddr, holderRewardPerBlock); - } } internal override void Initialize(ApplicationEngine engine) @@ -122,7 +112,7 @@ protected override void OnPersist(ApplicationEngine engine) base.OnPersist(engine); StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_NextValidators), () => new StorageItem()); storage.Value = GetValidators(engine.Snapshot).ToByteArray(); - DistributeGasForCommittee(engine); + RecordCumulativeGasByBlock(engine); } [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] From 94046163f481d3307db180ae591b7cf852b2309b Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 16:43:34 +0800 Subject: [PATCH 04/27] optimize --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index e9dd8f9b3f..3fa5a7bc77 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -74,18 +74,16 @@ private void RecordCumulativeGasByBlock(ApplicationEngine engine) { var gasPerBlock = GetGasPerBlock(engine.Snapshot); RewardRatio rewardRatio = GetRewardRatio(engine.Snapshot); - BigInteger holderRewardPerBlock = gasPerBlock * rewardRatio.NeoHolder / 100; // The final calculation should be divided by the total number of NEO + var holderRewards = gasPerBlock * rewardRatio.NeoHolder / 100; // The final calculation should be divided by the total number of NEO // Keep track of incremental gains of neo holders - var index = engine.Snapshot.PersistingBlock.Index; - var holderRewards = holderRewardPerBlock; - var holderRewardKey = CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue - index - 1); - var holderBorderKey = CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue); - var enumerator = engine.Snapshot.Storages.FindRange(holderRewardKey, holderBorderKey).GetEnumerator(); + var holderKeyLeft = CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue - engine.Snapshot.PersistingBlock.Index - 1); + var holderKeyRight = CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue); + var enumerator = engine.Snapshot.Storages.FindRange(holderKeyLeft, holderKeyRight).GetEnumerator(); if (enumerator.MoveNext()) holderRewards += new BigInteger(enumerator.Current.Value.Value); - engine.Snapshot.Storages.Add(holderRewardKey, new StorageItem() { Value = holderRewards.ToByteArray() }); + engine.Snapshot.Storages.Add(holderKeyLeft, new StorageItem() { Value = holderRewards.ToByteArray() }); } internal override void Initialize(ApplicationEngine engine) From f63ba942ca54714f3212bba042f552e1398df913 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 16:50:19 +0800 Subject: [PATCH 05/27] add ut --- .../Native/Tokens/UT_NeoToken.cs | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 3885c3d844..56559f84f5 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -571,6 +571,29 @@ public void TestTotalSupply() NativeContract.NEO.TotalSupply(snapshot).Should().Be(new BigInteger(100000000)); } + [TestMethod] + public void TestEconomicParameter() + { + var snapshot = Blockchain.Singleton.GetSnapshot(); + (bool, bool) ret1 = Check_SetGasPerByte(snapshot, 2 * NativeContract.GAS.Factor); + ret1.Item2.Should().BeTrue(); + ret1.Item1.Should().BeTrue(); + + (BigInteger, bool) result = Check_GetGasPerBlock(snapshot); + result.Item2.Should().BeTrue(); + result.Item1.Should().Be(2 * NativeContract.GAS.Factor); + + ret1 = Check_SetRewardRatio(snapshot, 10, 10, 80); + ret1.Item2.Should().BeTrue(); + ret1.Item1.Should().BeTrue(); + + (VM.Types.Array, bool) result2 = Check_GetEconomicParameter(snapshot, "getRewardRatio"); + result2.Item2.Should().BeTrue(); + result2.Item1[0].GetInteger().Should().Be(10); + result2.Item1[1].GetInteger().Should().Be(10); + result2.Item1[2].GetInteger().Should().Be(80); + } + [TestMethod] public void TestUnclaimedGas() { @@ -644,6 +667,108 @@ public void TestVote() return (true, result.GetBoolean()); } + internal static (bool Value, bool State) Check_SetRewardRatio(StoreView snapshot, BigInteger holder, BigInteger committee, BigInteger voters) + { + ECPoint[] committees = NativeContract.NEO.GetCommittee(snapshot); + UInt160 committeesMultisign = Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); + var engine = ApplicationEngine.Create(TriggerType.Application, + new Nep5NativeContractExtensions.ManualWitness(committeesMultisign), snapshot); + + engine.LoadScript(NativeContract.NEO.Script); + + var script = new ScriptBuilder(); + script.EmitPush(voters); + script.EmitPush(committee); + script.EmitPush(holder); + script.EmitPush(3); + script.Emit(OpCode.PACK); + script.EmitPush("setRewardRatio"); + engine.LoadScript(script.ToArray()); + + if (engine.Execute() == VMState.FAULT) + { + return (false, false); + } + + var result = engine.ResultStack.Pop(); + result.Should().BeOfType(typeof(VM.Types.Boolean)); + + return (result.GetBoolean(), true); + } + + internal static (bool Value, bool State) Check_SetGasPerByte(StoreView snapshot, BigInteger value) + { + ECPoint[] committees = NativeContract.NEO.GetCommittee(snapshot); + UInt160 committeesMultisign = Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); + var engine = ApplicationEngine.Create(TriggerType.Application, + new Nep5NativeContractExtensions.ManualWitness(committeesMultisign), snapshot); + + engine.LoadScript(NativeContract.NEO.Script); + + var script = new ScriptBuilder(); + script.EmitPush(value); + script.EmitPush(1); + script.Emit(OpCode.PACK); + script.EmitPush("setGasPerBlock"); + engine.LoadScript(script.ToArray()); + + if (engine.Execute() == VMState.FAULT) + { + return (false, false); + } + + var result = engine.ResultStack.Pop(); + result.Should().BeOfType(typeof(VM.Types.Boolean)); + + return (result.GetBoolean(), true); + } + + internal static (BigInteger Value, bool State) Check_GetGasPerBlock(StoreView snapshot) + { + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + + engine.LoadScript(NativeContract.NEO.Script); + + var script = new ScriptBuilder(); + script.EmitPush(0); + script.Emit(OpCode.PACK); + script.EmitPush("getGasPerBlock"); + engine.LoadScript(script.ToArray()); + + if (engine.Execute() == VMState.FAULT) + { + return (BigInteger.Zero, false); + } + + var result = engine.ResultStack.Pop(); + result.Should().BeOfType(typeof(VM.Types.Integer)); + + return (((VM.Types.Integer)result).GetInteger(), true); + } + + internal static (VM.Types.Array Value, bool State) Check_GetEconomicParameter(StoreView snapshot, string method) + { + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + + engine.LoadScript(NativeContract.NEO.Script); + + var script = new ScriptBuilder(); + script.EmitPush(0); + script.Emit(OpCode.PACK); + script.EmitPush(method); + engine.LoadScript(script.ToArray()); + + if (engine.Execute() == VMState.FAULT) + { + return (null, false); + } + + var result = engine.ResultStack.Pop(); + result.Should().BeOfType(typeof(VM.Types.Array)); + + return ((VM.Types.Array)result, true); + } + internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] account, byte[] pubkey, bool signAccount) { var engine = ApplicationEngine.Create(TriggerType.Application, From c63c099c0b19df1a26ab7d9ec263a197e4864715 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 21:39:41 +0800 Subject: [PATCH 06/27] hard code reward ratio --- .../SmartContract/Native/Tokens/NeoToken.cs | 62 ++++--------------- .../Native/Tokens/UT_GasToken.cs | 20 +++--- .../Native/Tokens/UT_NeoToken.cs | 29 +++------ 3 files changed, 30 insertions(+), 81 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 3fa5a7bc77..19226e6254 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -29,7 +29,12 @@ public sealed class NeoToken : Nep5Token private const byte Prefix_GasPerBlock = 29; private const byte Prefix_RewardRatio = 15; - private const byte Prefix_HolderRewardPerBlock = 27; + + private readonly BigInteger GasPerBlock = 5 * GAS.Factor; + + private const byte NeoHolderRewardRatio = 10; + private const byte CommitteeRewardRatio = 5; + private const byte VoterRewardRatio = 85; internal NeoToken() { @@ -63,27 +68,9 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta { if (value.IsZero || start >= end) return BigInteger.Zero; if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value)); - var endRewardItem = snapshot.Storages.TryGet(CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue - end - 1)); - var startRewardItem = snapshot.Storages.TryGet(CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue - start - 1)); - BigInteger startReward = startRewardItem is null ? 0 : new BigInteger(startRewardItem.Value); - BigInteger endReward = endRewardItem is null ? 0 : new BigInteger(endRewardItem.Value); - return value * (endReward - startReward) / TotalAmount; - } - - private void RecordCumulativeGasByBlock(ApplicationEngine engine) - { - var gasPerBlock = GetGasPerBlock(engine.Snapshot); - RewardRatio rewardRatio = GetRewardRatio(engine.Snapshot); - var holderRewards = gasPerBlock * rewardRatio.NeoHolder / 100; // The final calculation should be divided by the total number of NEO - - // Keep track of incremental gains of neo holders - - var holderKeyLeft = CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue - engine.Snapshot.PersistingBlock.Index - 1); - var holderKeyRight = CreateStorageKey(Prefix_HolderRewardPerBlock).Add(uint.MaxValue); - var enumerator = engine.Snapshot.Storages.FindRange(holderKeyLeft, holderKeyRight).GetEnumerator(); - if (enumerator.MoveNext()) - holderRewards += new BigInteger(enumerator.Current.Value.Value); - engine.Snapshot.Storages.Add(holderKeyLeft, new StorageItem() { Value = holderRewards.ToByteArray() }); + var gasPerBlock = GetGasPerBlock(snapshot); + var NeoHolderRewardRatio = GetRewardRatio(snapshot).NeoHolder; + return value * gasPerBlock * (end - start) * NeoHolderRewardRatio / 100 / TotalAmount; } internal override void Initialize(ApplicationEngine engine) @@ -92,13 +79,13 @@ internal override void Initialize(ApplicationEngine engine) engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock), new StorageItem { - Value = (5 * GAS.Factor).ToByteArray() + Value = GasPerBlock.ToByteArray() }); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_RewardRatio), new StorageItem(new RewardRatio { - NeoHolder = 10, - Committee = 5, - Voter = 85 + NeoHolder = NeoHolderRewardRatio, + Committee = CommitteeRewardRatio, + Voter = VoterRewardRatio })); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0])); @@ -110,29 +97,6 @@ protected override void OnPersist(ApplicationEngine engine) base.OnPersist(engine); StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_NextValidators), () => new StorageItem()); storage.Value = GetValidators(engine.Snapshot).ToByteArray(); - RecordCumulativeGasByBlock(engine); - } - - [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] - private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) - { - if (gasPerBlock < 0 || gasPerBlock > 8 * GAS.Factor) return false; - if (!CheckCommittees(engine)) return false; - StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)); - item.Value = gasPerBlock.ToByteArray(); - return true; - } - - [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] - private bool SetRewardRatio(ApplicationEngine engine, byte neoHoldersRewardRatio, byte committeesRewardRatio, byte votersRewardRatio) - { - if (checked(neoHoldersRewardRatio + committeesRewardRatio + votersRewardRatio) != 100) return false; - if (!CheckCommittees(engine)) return false; - RewardRatio rewardRatio = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_RewardRatio), () => new StorageItem(new RewardRatio())).GetInteroperable(); - rewardRatio.NeoHolder = neoHoldersRewardRatio; - rewardRatio.Committee = committeesRewardRatio; - rewardRatio.Voter = votersRewardRatio; - return true; } [ContractMethod(1_00000000, CallFlags.AllowStates)] diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 9f26ecc79b..6b84f62c01 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -52,7 +52,7 @@ public void Check_BalanceOfTransferAndBurn() snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); var unclaim = UT_NeoToken.Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(1000 * 100000000L)); + unclaim.Value.Should().Be(new BigInteger(0.5 * 1000 * 100000000L)); unclaim.State.Should().BeTrue(); // Transfer @@ -61,7 +61,7 @@ public void Check_BalanceOfTransferAndBurn() NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(100000000); NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(0); - NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(30001000_00000000); + NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(30000500_00000000); NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(0); // Check unclaim @@ -71,7 +71,7 @@ public void Check_BalanceOfTransferAndBurn() unclaim.State.Should().BeTrue(); supply = NativeContract.GAS.TotalSupply(snapshot); - supply.Should().Be(30001000_00000000); + supply.Should().Be(3000050000000000); snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 5); // Gas @@ -79,13 +79,13 @@ public void Check_BalanceOfTransferAndBurn() keyCount = snapshot.Storages.GetChangeSet().Count(); - NativeContract.GAS.Transfer(snapshot, from, to, 30001000_00000000, false).Should().BeFalse(); // Not signed - NativeContract.GAS.Transfer(snapshot, from, to, 30001000_00000001, true).Should().BeFalse(); // More than balance - NativeContract.GAS.Transfer(snapshot, from, to, 30001000_00000000, true).Should().BeTrue(); // All balance + NativeContract.GAS.Transfer(snapshot, from, to, 30000500_00000000, false).Should().BeFalse(); // Not signed + NativeContract.GAS.Transfer(snapshot, from, to, 30000500_00000001, true).Should().BeFalse(); // More than balance + NativeContract.GAS.Transfer(snapshot, from, to, 30000500_00000000, true).Should().BeTrue(); // All balance // Balance of - NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30001000_00000000); + NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30000500_00000000); NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(0); snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 1); // All @@ -101,19 +101,19 @@ public void Check_BalanceOfTransferAndBurn() // Burn more than expected Assert.ThrowsException(() => - NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(30006000_00000001))); + NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(30000500_00000001))); // Real burn NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(1)); - NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000099999999999); + NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000049999999999); keyCount.Should().Be(snapshot.Storages.GetChangeSet().Count()); // Burn all - NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000099999999999)); + NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000049999999999)); (keyCount - 1).Should().Be(snapshot.Storages.GetChangeSet().Count()); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 56559f84f5..bb396d0de5 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -186,11 +186,8 @@ public void Check_UnclaimedGas() byte[] from = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); - snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 1000 - 1), new StorageItem() { Value = new BigInteger(1000 * 100000000L).ToByteArray() }); - snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); - var unclaim = Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(1000 * 100000000L)); + unclaim.Value.Should().Be(new BigInteger(0.5 * 1000 * 100000000L)); unclaim.State.Should().BeTrue(); unclaim = Check_UnclaimedGas(snapshot, new byte[19]); @@ -341,11 +338,8 @@ public void Check_Transfer() // Check unclaim - snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 1000 - 1), new StorageItem() { Value = new BigInteger(1000 * 100000000L).ToByteArray() }); - snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); - var unclaim = Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(1000 * 100000000L)); + unclaim.Value.Should().Be(new BigInteger(0.5 * 1000 * 100000000L)); unclaim.State.Should().BeTrue(); // Transfer @@ -361,7 +355,7 @@ public void Check_Transfer() unclaim.Value.Should().Be(new BigInteger(0)); unclaim.State.Should().BeTrue(); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 6); // Gas + new balance + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + new balance // Return balance @@ -449,9 +443,7 @@ public void TestCalculateBonus() { Balance = 100 })); - snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 100 - 1), new StorageItem() { Value = new BigInteger(100 * 100000000L).ToByteArray() }); - snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); - NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 100).Should().Be(new BigInteger(100 * 100)); + NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 100).Should().Be(new BigInteger(0.5 * 100 * 100)); snapshot.Storages.Delete(key); } @@ -575,23 +567,16 @@ public void TestTotalSupply() public void TestEconomicParameter() { var snapshot = Blockchain.Singleton.GetSnapshot(); - (bool, bool) ret1 = Check_SetGasPerByte(snapshot, 2 * NativeContract.GAS.Factor); - ret1.Item2.Should().BeTrue(); - ret1.Item1.Should().BeTrue(); (BigInteger, bool) result = Check_GetGasPerBlock(snapshot); result.Item2.Should().BeTrue(); - result.Item1.Should().Be(2 * NativeContract.GAS.Factor); - - ret1 = Check_SetRewardRatio(snapshot, 10, 10, 80); - ret1.Item2.Should().BeTrue(); - ret1.Item1.Should().BeTrue(); + result.Item1.Should().Be(5 * NativeContract.GAS.Factor); (VM.Types.Array, bool) result2 = Check_GetEconomicParameter(snapshot, "getRewardRatio"); result2.Item2.Should().BeTrue(); result2.Item1[0].GetInteger().Should().Be(10); - result2.Item1[1].GetInteger().Should().Be(10); - result2.Item1[2].GetInteger().Should().Be(80); + result2.Item1[1].GetInteger().Should().Be(5); + result2.Item1[2].GetInteger().Should().Be(85); } [TestMethod] From ef9f5c51dfcef1f960a09077a8629b1abc3b64d1 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 22:51:36 +0800 Subject: [PATCH 07/27] remove useless code --- .../Native/Tokens/UT_NeoToken.cs | 66 ------------------- 1 file changed, 66 deletions(-) diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index bb396d0de5..aee6cb6669 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -652,62 +652,6 @@ public void TestVote() return (true, result.GetBoolean()); } - internal static (bool Value, bool State) Check_SetRewardRatio(StoreView snapshot, BigInteger holder, BigInteger committee, BigInteger voters) - { - ECPoint[] committees = NativeContract.NEO.GetCommittee(snapshot); - UInt160 committeesMultisign = Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); - var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep5NativeContractExtensions.ManualWitness(committeesMultisign), snapshot); - - engine.LoadScript(NativeContract.NEO.Script); - - var script = new ScriptBuilder(); - script.EmitPush(voters); - script.EmitPush(committee); - script.EmitPush(holder); - script.EmitPush(3); - script.Emit(OpCode.PACK); - script.EmitPush("setRewardRatio"); - engine.LoadScript(script.ToArray()); - - if (engine.Execute() == VMState.FAULT) - { - return (false, false); - } - - var result = engine.ResultStack.Pop(); - result.Should().BeOfType(typeof(VM.Types.Boolean)); - - return (result.GetBoolean(), true); - } - - internal static (bool Value, bool State) Check_SetGasPerByte(StoreView snapshot, BigInteger value) - { - ECPoint[] committees = NativeContract.NEO.GetCommittee(snapshot); - UInt160 committeesMultisign = Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); - var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep5NativeContractExtensions.ManualWitness(committeesMultisign), snapshot); - - engine.LoadScript(NativeContract.NEO.Script); - - var script = new ScriptBuilder(); - script.EmitPush(value); - script.EmitPush(1); - script.Emit(OpCode.PACK); - script.EmitPush("setGasPerBlock"); - engine.LoadScript(script.ToArray()); - - if (engine.Execute() == VMState.FAULT) - { - return (false, false); - } - - var result = engine.ResultStack.Pop(); - result.Should().BeOfType(typeof(VM.Types.Boolean)); - - return (result.GetBoolean(), true); - } - internal static (BigInteger Value, bool State) Check_GetGasPerBlock(StoreView snapshot) { var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); @@ -914,15 +858,5 @@ internal static (bool State, bool Result) Check_UnregisterCandidate(StoreView sn return (true, result.GetBoolean()); } - - internal static StorageKey CreateStorageKey(byte prefix, uint key) - { - return CreateStorageKey(prefix, BitConverter.GetBytes(key)); - } - - internal static StorageKey CreateStorageKey(byte prefix, ISerializable keyLeft, uint keyRight) - { - return CreateStorageKey(prefix, keyLeft.ToArray().Concat(BitConverter.GetBytes(keyRight)).ToArray()); - } } } From 0d0a40c56420c3e7eb7708ae1cdcb9a9f24a25fe Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 22:56:23 +0800 Subject: [PATCH 08/27] fix ut --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 19226e6254..6028b42f38 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -30,7 +30,7 @@ public sealed class NeoToken : Nep5Token private const byte Prefix_GasPerBlock = 29; private const byte Prefix_RewardRatio = 15; - private readonly BigInteger GasPerBlock = 5 * GAS.Factor; + private readonly BigInteger GasPerBlock = 5; private const byte NeoHolderRewardRatio = 10; private const byte CommitteeRewardRatio = 5; @@ -79,7 +79,7 @@ internal override void Initialize(ApplicationEngine engine) engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock), new StorageItem { - Value = GasPerBlock.ToByteArray() + Value = (GasPerBlock * GAS.Factor).ToByteArray() }); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_RewardRatio), new StorageItem(new RewardRatio { From dcd2df4e0e542494c7eb5f137a398c034fdbcb00 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 22:59:03 +0800 Subject: [PATCH 09/27] remove useless code --- .../SmartContract/Native/Tokens/NeoToken.cs | 22 ------------------- .../Native/Tokens/UT_GasToken.cs | 3 --- 2 files changed, 25 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 6028b42f38..f796e2a856 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -215,28 +215,6 @@ public UInt160 GetCommitteeAddress(StoreView snapshot) return Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); } - public bool CheckCommittees(ApplicationEngine engine) - { - UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); - return engine.CheckWitnessInternal(committeeMultiSigAddr); - } - - private (ECPoint PublicKey, BigInteger Votes)[] GetCommitteeVotes(StoreView snapshot) - { - (ECPoint PublicKey, BigInteger Votes)[] committeeVotes = new (ECPoint PublicKey, BigInteger Votes)[ProtocolSettings.Default.CommitteeMembersCount]; - var i = 0; - foreach (var commiteePubKey in GetCommitteeMembers(snapshot)) - { - var item = snapshot.Storages.TryGet(CreateStorageKey(Prefix_Candidate).Add(commiteePubKey)); - if (item is null) - committeeVotes[i] = (commiteePubKey, BigInteger.Zero); - else - committeeVotes[i] = (commiteePubKey, item.GetInteroperable().Votes); - i++; - } - return committeeVotes; - } - private IEnumerable GetCommitteeMembers(StoreView snapshot) { decimal votersCount = (decimal)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_VotersCount)]; diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 6b84f62c01..9478c7ed97 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -48,9 +48,6 @@ public void Check_BalanceOfTransferAndBurn() // Check unclaim - snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 1000 - 1), new StorageItem() { Value = new BigInteger(1000 * 100000000L).ToByteArray() }); - snapshot.Storages.Add(CreateStorageKey(27, uint.MaxValue - 0 - 1), new StorageItem() { Value = new BigInteger(0).ToByteArray() }); - var unclaim = UT_NeoToken.Check_UnclaimedGas(snapshot, from); unclaim.Value.Should().Be(new BigInteger(0.5 * 1000 * 100000000L)); unclaim.State.Should().BeTrue(); From c3223b549fea1624245cf9041215f8c7a6f6f6dd Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 23:02:24 +0800 Subject: [PATCH 10/27] decrease fee --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index f796e2a856..d558bfb9b5 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -99,13 +99,13 @@ protected override void OnPersist(ApplicationEngine engine) storage.Value = GetValidators(engine.Snapshot).ToByteArray(); } - [ContractMethod(1_00000000, CallFlags.AllowStates)] + [ContractMethod(0_01000000, CallFlags.AllowStates)] public BigInteger GetGasPerBlock(StoreView snapshot) { return new BigInteger(snapshot.Storages.TryGet(CreateStorageKey(Prefix_GasPerBlock)).Value); } - [ContractMethod(1_00000000, CallFlags.AllowStates)] + [ContractMethod(0_01000000, CallFlags.AllowStates)] internal RewardRatio GetRewardRatio(StoreView snapshot) { return snapshot.Storages.TryGet(CreateStorageKey(Prefix_RewardRatio)).GetInteroperable(); From 0b7a1eb65ca6fa4dd44b0653fa0242df34a15c49 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 17 Aug 2020 23:12:41 +0800 Subject: [PATCH 11/27] fix ut --- tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 9478c7ed97..0a25d9973a 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -70,7 +70,7 @@ public void Check_BalanceOfTransferAndBurn() supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(3000050000000000); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 5); // Gas + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 3); // Gas // Transfer From c2e506545ea7a2734eeaf951a256454d6f529396 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 18 Aug 2020 14:36:49 +0800 Subject: [PATCH 12/27] Remove useless code --- .../SmartContract/Native/Tokens/NeoToken.cs | 35 ------------------- .../Native/Tokens/UT_NeoToken.cs | 29 --------------- 2 files changed, 64 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index d558bfb9b5..cc6e3e4164 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -26,9 +26,7 @@ public sealed class NeoToken : Nep5Token private const byte Prefix_VotersCount = 1; private const byte Prefix_Candidate = 33; private const byte Prefix_NextValidators = 14; - private const byte Prefix_GasPerBlock = 29; - private const byte Prefix_RewardRatio = 15; private readonly BigInteger GasPerBlock = 5; @@ -69,7 +67,6 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta if (value.IsZero || start >= end) return BigInteger.Zero; if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value)); var gasPerBlock = GetGasPerBlock(snapshot); - var NeoHolderRewardRatio = GetRewardRatio(snapshot).NeoHolder; return value * gasPerBlock * (end - start) * NeoHolderRewardRatio / 100 / TotalAmount; } @@ -81,12 +78,6 @@ internal override void Initialize(ApplicationEngine engine) { Value = (GasPerBlock * GAS.Factor).ToByteArray() }); - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_RewardRatio), new StorageItem(new RewardRatio - { - NeoHolder = NeoHolderRewardRatio, - Committee = CommitteeRewardRatio, - Voter = VoterRewardRatio - })); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0])); Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), TotalAmount); @@ -105,12 +96,6 @@ public BigInteger GetGasPerBlock(StoreView snapshot) return new BigInteger(snapshot.Storages.TryGet(CreateStorageKey(Prefix_GasPerBlock)).Value); } - [ContractMethod(0_01000000, CallFlags.AllowStates)] - internal RewardRatio GetRewardRatio(StoreView snapshot) - { - return snapshot.Storages.TryGet(CreateStorageKey(Prefix_RewardRatio)).GetInteroperable(); - } - [ContractMethod(0_03000000, CallFlags.AllowStates)] public BigInteger UnclaimedGas(StoreView snapshot, UInt160 account, uint end) { @@ -274,25 +259,5 @@ public StackItem ToStackItem(ReferenceCounter referenceCounter) return new Struct(referenceCounter) { Registered, Votes }; } } - - internal class RewardRatio : IInteroperable - { - public int NeoHolder; - public int Committee; - public int Voter; - - public void FromStackItem(StackItem stackItem) - { - VM.Types.Array array = (VM.Types.Array)stackItem; - NeoHolder = (int)array[0].GetInteger(); - Committee = (int)array[1].GetInteger(); - Voter = (int)array[2].GetInteger(); - } - - public StackItem ToStackItem(ReferenceCounter referenceCounter) - { - return new VM.Types.Array() { new Integer(NeoHolder), new Integer(Committee), new Integer(Voter) }; - } - } } } diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index aee6cb6669..9144af05f7 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -571,12 +571,6 @@ public void TestEconomicParameter() (BigInteger, bool) result = Check_GetGasPerBlock(snapshot); result.Item2.Should().BeTrue(); result.Item1.Should().Be(5 * NativeContract.GAS.Factor); - - (VM.Types.Array, bool) result2 = Check_GetEconomicParameter(snapshot, "getRewardRatio"); - result2.Item2.Should().BeTrue(); - result2.Item1[0].GetInteger().Should().Be(10); - result2.Item1[1].GetInteger().Should().Be(5); - result2.Item1[2].GetInteger().Should().Be(85); } [TestMethod] @@ -675,29 +669,6 @@ internal static (BigInteger Value, bool State) Check_GetGasPerBlock(StoreView sn return (((VM.Types.Integer)result).GetInteger(), true); } - internal static (VM.Types.Array Value, bool State) Check_GetEconomicParameter(StoreView snapshot, string method) - { - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); - - engine.LoadScript(NativeContract.NEO.Script); - - var script = new ScriptBuilder(); - script.EmitPush(0); - script.Emit(OpCode.PACK); - script.EmitPush(method); - engine.LoadScript(script.ToArray()); - - if (engine.Execute() == VMState.FAULT) - { - return (null, false); - } - - var result = engine.ResultStack.Pop(); - result.Should().BeOfType(typeof(VM.Types.Array)); - - return ((VM.Types.Array)result, true); - } - internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] account, byte[] pubkey, bool signAccount) { var engine = ApplicationEngine.Create(TriggerType.Application, From 3d0bb19517e4682db90616c146a246dd5c09157b Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 18 Aug 2020 14:39:10 +0800 Subject: [PATCH 13/27] Update NeoToken.cs --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index cc6e3e4164..dd87c9d4c8 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -28,8 +28,6 @@ public sealed class NeoToken : Nep5Token private const byte Prefix_NextValidators = 14; private const byte Prefix_GasPerBlock = 29; - private readonly BigInteger GasPerBlock = 5; - private const byte NeoHolderRewardRatio = 10; private const byte CommitteeRewardRatio = 5; private const byte VoterRewardRatio = 85; @@ -76,7 +74,7 @@ internal override void Initialize(ApplicationEngine engine) engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock), new StorageItem { - Value = (GasPerBlock * GAS.Factor).ToByteArray() + Value = (5 * GAS.Factor).ToByteArray() }); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0])); From e992aadc3c2cd3c662e363b6cec229077f663fd6 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Tue, 18 Aug 2020 19:40:41 +0800 Subject: [PATCH 14/27] add SetGasPerBlock --- .../SmartContract/Native/NativeContract.cs | 6 +++ .../SmartContract/Native/PolicyContract.cs | 6 --- .../SmartContract/Native/Tokens/NeoToken.cs | 43 +++++++++++++++++-- .../Native/Tokens/UT_NeoToken.cs | 33 ++++++++++++++ 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index adf83a3b1c..31b6a79a0c 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -134,6 +134,12 @@ protected virtual void OnPersist(ApplicationEngine engine) throw new InvalidOperationException(); } + protected bool CheckCommittees(ApplicationEngine engine) + { + UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); + return engine.CheckWitnessInternal(committeeMultiSigAddr); + } + public ApplicationEngine TestCall(string operation, params object[] args) { using (ScriptBuilder sb = new ScriptBuilder()) diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 244b64deb2..189a0b2a15 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -25,12 +25,6 @@ public PolicyContract() Manifest.Features = ContractFeatures.HasStorage; } - private bool CheckCommittees(ApplicationEngine engine) - { - UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); - return engine.CheckWitnessInternal(committeeMultiSigAddr); - } - [ContractMethod(0_01000000, CallFlags.AllowStates)] public uint GetMaxTransactionsPerBlock(StoreView snapshot) { diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index dd87c9d4c8..1920a080cf 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -64,15 +64,35 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta { if (value.IsZero || start >= end) return BigInteger.Zero; if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value)); - var gasPerBlock = GetGasPerBlock(snapshot); - return value * gasPerBlock * (end - start) * NeoHolderRewardRatio / 100 / TotalAmount; + + StorageKey keyLeft = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - end); + StorageKey keyRight = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue); + var enumerator = snapshot.Storages.FindRange(keyLeft, keyRight).GetEnumerator(); + BigInteger sum = 0; + uint right = end; + while (enumerator.MoveNext()) + { + var gasPerBlock = new BigInteger(enumerator.Current.Value.Value); + var index = uint.MaxValue - BitConverter.ToUInt32(enumerator.Current.Key.Key.Skip(1).ToArray()) - 1; + if (index <= start) + { + sum += gasPerBlock * (right - start); + break; + } + else + { + sum += gasPerBlock * (right - index); + right = index; + } + } + return value * sum * NeoHolderRewardRatio / 100 / TotalAmount; } internal override void Initialize(ApplicationEngine engine) { // Initialize economic parameters - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock), new StorageItem + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - 1), new StorageItem { Value = (5 * GAS.Factor).ToByteArray() }); @@ -88,10 +108,25 @@ protected override void OnPersist(ApplicationEngine engine) storage.Value = GetValidators(engine.Snapshot).ToByteArray(); } + [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] + private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) + { + if (gasPerBlock < 0 || gasPerBlock > 10 * GAS.Factor) return false; + if (!CheckCommittees(engine)) return false; + StorageKey key = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - engine.Snapshot.PersistingBlock.Index - 1); + StorageItem item = engine.Snapshot.Storages.GetAndChange(key, () => new StorageItem { Value = BigInteger.Zero.ToByteArray() }); + item.Value = gasPerBlock.ToByteArray(); + return true; + } + [ContractMethod(0_01000000, CallFlags.AllowStates)] public BigInteger GetGasPerBlock(StoreView snapshot) { - return new BigInteger(snapshot.Storages.TryGet(CreateStorageKey(Prefix_GasPerBlock)).Value); + StorageKey keyLeft = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - snapshot.PersistingBlock.Index - 1); + StorageKey keyRight = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue); + var enumerator = snapshot.Storages.FindRange(keyLeft, keyRight).GetEnumerator(); + enumerator.MoveNext(); + return new BigInteger(enumerator.Current.Value.Value); } [ContractMethod(0_03000000, CallFlags.AllowStates)] diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 9144af05f7..4fae26a467 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -415,6 +415,8 @@ public void Check_BadScript() public void TestCalculateBonus() { var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.PersistingBlock = new Block { Index = 0 }; + StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); // Fault: balance < 0 @@ -567,10 +569,16 @@ public void TestTotalSupply() public void TestEconomicParameter() { var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.PersistingBlock = new Block { Index = 0 }; (BigInteger, bool) result = Check_GetGasPerBlock(snapshot); result.Item2.Should().BeTrue(); result.Item1.Should().Be(5 * NativeContract.GAS.Factor); + + snapshot.PersistingBlock = new Block { Index = 10 }; + (VM.Types.Boolean, bool) result1 = Check_SetGasPerBlock(snapshot, 10 * NativeContract.GAS.Factor); + result1.Item2.Should().BeTrue(); + result1.Item1.GetBoolean().Should().BeTrue(); } [TestMethod] @@ -669,6 +677,31 @@ internal static (BigInteger Value, bool State) Check_GetGasPerBlock(StoreView sn return (((VM.Types.Integer)result).GetInteger(), true); } + internal static (VM.Types.Boolean Value, bool State) Check_SetGasPerBlock(StoreView snapshot, BigInteger gasPerBlock) + { + UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); + var engine = ApplicationEngine.Create(TriggerType.Application, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), snapshot); + + engine.LoadScript(NativeContract.NEO.Script); + + var script = new ScriptBuilder(); + script.EmitPush(gasPerBlock); + script.EmitPush(1); + script.Emit(OpCode.PACK); + script.EmitPush("setGasPerBlock"); + engine.LoadScript(script.ToArray()); + + if (engine.Execute() == VMState.FAULT) + { + return (false, false); + } + + var result = engine.ResultStack.Pop(); + result.Should().BeOfType(typeof(VM.Types.Boolean)); + + return (((VM.Types.Boolean)result).GetBoolean(), true); + } + internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] account, byte[] pubkey, bool signAccount) { var engine = ApplicationEngine.Create(TriggerType.Application, From 3696bb4b4c8b5f7755ee34579ab9c1f06d9cefe9 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 19 Aug 2020 16:36:21 +0800 Subject: [PATCH 15/27] Rename --- src/neo/SmartContract/Native/NativeContract.cs | 12 ++++++------ src/neo/SmartContract/Native/PolicyContract.cs | 12 ++++++------ src/neo/SmartContract/Native/Tokens/NeoToken.cs | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index 31b6a79a0c..54ef2c5d6d 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -77,6 +77,12 @@ protected NativeContract() contractsHashDictionary.Add(Hash, this); } + protected bool CheckCommittee(ApplicationEngine engine) + { + UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); + return engine.CheckWitnessInternal(committeeMultiSigAddr); + } + private protected KeyBuilder CreateStorageKey(byte prefix) { return new KeyBuilder(Id, prefix); @@ -134,12 +140,6 @@ protected virtual void OnPersist(ApplicationEngine engine) throw new InvalidOperationException(); } - protected bool CheckCommittees(ApplicationEngine engine) - { - UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); - return engine.CheckWitnessInternal(committeeMultiSigAddr); - } - public ApplicationEngine TestCall(string operation, params object[] args) { using (ScriptBuilder sb = new ScriptBuilder()) diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 189a0b2a15..32f90ba89d 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -87,7 +87,7 @@ public bool IsAnyAccountBlocked(StoreView snapshot, params UInt160[] hashes) [ContractMethod(0_03000000, CallFlags.AllowModifyStates)] private bool SetMaxBlockSize(ApplicationEngine engine, uint value) { - if (!CheckCommittees(engine)) return false; + if (!CheckCommittee(engine)) return false; if (Network.P2P.Message.PayloadMaxSize <= value) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSize), () => new StorageItem()); storage.Set(value); @@ -97,7 +97,7 @@ private bool SetMaxBlockSize(ApplicationEngine engine, uint value) [ContractMethod(0_03000000, CallFlags.AllowModifyStates)] private bool SetMaxTransactionsPerBlock(ApplicationEngine engine, uint value) { - if (!CheckCommittees(engine)) return false; + if (!CheckCommittee(engine)) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxTransactionsPerBlock), () => new StorageItem()); storage.Set(value); return true; @@ -106,7 +106,7 @@ private bool SetMaxTransactionsPerBlock(ApplicationEngine engine, uint value) [ContractMethod(0_03000000, CallFlags.AllowModifyStates)] private bool SetMaxBlockSystemFee(ApplicationEngine engine, long value) { - if (!CheckCommittees(engine)) return false; + if (!CheckCommittee(engine)) return false; if (value <= 4007600) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSystemFee), () => new StorageItem()); storage.Set(value); @@ -116,7 +116,7 @@ private bool SetMaxBlockSystemFee(ApplicationEngine engine, long value) [ContractMethod(0_03000000, CallFlags.AllowModifyStates)] private bool SetFeePerByte(ApplicationEngine engine, long value) { - if (!CheckCommittees(engine)) return false; + if (!CheckCommittee(engine)) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_FeePerByte), () => new StorageItem()); storage.Set(value); return true; @@ -125,7 +125,7 @@ private bool SetFeePerByte(ApplicationEngine engine, long value) [ContractMethod(0_03000000, CallFlags.AllowModifyStates)] private bool BlockAccount(ApplicationEngine engine, UInt160 account) { - if (!CheckCommittees(engine)) return false; + if (!CheckCommittee(engine)) return false; StorageKey key = CreateStorageKey(Prefix_BlockedAccounts); StorageItem storage = engine.Snapshot.Storages.GetOrAdd(key, () => new StorageItem(new byte[1])); List accounts = storage.GetSerializableList(); @@ -139,7 +139,7 @@ private bool BlockAccount(ApplicationEngine engine, UInt160 account) [ContractMethod(0_03000000, CallFlags.AllowModifyStates)] private bool UnblockAccount(ApplicationEngine engine, UInt160 account) { - if (!CheckCommittees(engine)) return false; + if (!CheckCommittee(engine)) return false; StorageKey key = CreateStorageKey(Prefix_BlockedAccounts); StorageItem storage = engine.Snapshot.Storages.TryGet(key); if (storage is null) return false; diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 1920a080cf..790918b6c6 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -112,7 +112,7 @@ protected override void OnPersist(ApplicationEngine engine) private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) { if (gasPerBlock < 0 || gasPerBlock > 10 * GAS.Factor) return false; - if (!CheckCommittees(engine)) return false; + if (!CheckCommittee(engine)) return false; StorageKey key = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - engine.Snapshot.PersistingBlock.Index - 1); StorageItem item = engine.Snapshot.Storages.GetAndChange(key, () => new StorageItem { Value = BigInteger.Zero.ToByteArray() }); item.Value = gasPerBlock.ToByteArray(); From b2834beec97e63ed5abe3313ed0f7f93127aeed5 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Wed, 19 Aug 2020 18:15:08 +0800 Subject: [PATCH 16/27] add KeyBuilder AddBigEndian --- src/neo/SmartContract/Native/KeyBuilder.cs | 7 +++++++ src/neo/SmartContract/Native/Tokens/NeoToken.cs | 14 +++++++------- .../SmartContract/Native/UT_KeyBuilder.cs | 4 ++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/neo/SmartContract/Native/KeyBuilder.cs b/src/neo/SmartContract/Native/KeyBuilder.cs index 79ae513df8..0461f87c79 100644 --- a/src/neo/SmartContract/Native/KeyBuilder.cs +++ b/src/neo/SmartContract/Native/KeyBuilder.cs @@ -1,7 +1,9 @@ +using Neo.Cryptography; using Neo.IO; using Neo.Ledger; using System; using System.IO; +using System.Linq; namespace Neo.SmartContract.Native { @@ -37,6 +39,11 @@ unsafe public KeyBuilder Add(T key) where T : unmanaged return Add(new ReadOnlySpan(&key, sizeof(T))); } + unsafe public KeyBuilder AddBigEndian(T key) where T : unmanaged + { + return Add(new ReadOnlySpan(&key, sizeof(T)).ToArray().Reverse().ToArray()); + } + public byte[] ToArray() { using (stream) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 790918b6c6..f5b84730a1 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -65,15 +65,15 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta if (value.IsZero || start >= end) return BigInteger.Zero; if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value)); - StorageKey keyLeft = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - end); - StorageKey keyRight = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue); + StorageKey keyLeft = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue - end); + StorageKey keyRight = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue); var enumerator = snapshot.Storages.FindRange(keyLeft, keyRight).GetEnumerator(); BigInteger sum = 0; uint right = end; while (enumerator.MoveNext()) { var gasPerBlock = new BigInteger(enumerator.Current.Value.Value); - var index = uint.MaxValue - BitConverter.ToUInt32(enumerator.Current.Key.Key.Skip(1).ToArray()) - 1; + var index = uint.MaxValue - BitConverter.ToUInt32(enumerator.Current.Key.Key.Skip(1).Reverse().ToArray()) - 1; if (index <= start) { sum += gasPerBlock * (right - start); @@ -92,7 +92,7 @@ internal override void Initialize(ApplicationEngine engine) { // Initialize economic parameters - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - 1), new StorageItem + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue - 1), new StorageItem { Value = (5 * GAS.Factor).ToByteArray() }); @@ -113,7 +113,7 @@ private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) { if (gasPerBlock < 0 || gasPerBlock > 10 * GAS.Factor) return false; if (!CheckCommittee(engine)) return false; - StorageKey key = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - engine.Snapshot.PersistingBlock.Index - 1); + StorageKey key = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue - engine.Snapshot.PersistingBlock.Index - 1); StorageItem item = engine.Snapshot.Storages.GetAndChange(key, () => new StorageItem { Value = BigInteger.Zero.ToByteArray() }); item.Value = gasPerBlock.ToByteArray(); return true; @@ -122,8 +122,8 @@ private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) [ContractMethod(0_01000000, CallFlags.AllowStates)] public BigInteger GetGasPerBlock(StoreView snapshot) { - StorageKey keyLeft = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue - snapshot.PersistingBlock.Index - 1); - StorageKey keyRight = CreateStorageKey(Prefix_GasPerBlock).Add(uint.MaxValue); + StorageKey keyLeft = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue - snapshot.PersistingBlock.Index - 1); + StorageKey keyRight = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue); var enumerator = snapshot.Storages.FindRange(keyLeft, keyRight).GetEnumerator(); enumerator.MoveNext(); return new BigInteger(enumerator.Current.Value.Value); diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_KeyBuilder.cs b/tests/neo.UnitTests/SmartContract/Native/UT_KeyBuilder.cs index 96552dc12e..9db398f0cb 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_KeyBuilder.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_KeyBuilder.cs @@ -30,6 +30,10 @@ public void Test() key = new KeyBuilder(1, 2); key = key.Add(new a() { x = 123 }); Assert.AreEqual("01000000027b000000", key.ToArray().ToHexString()); + + key = new KeyBuilder(1, 0); + key = key.AddBigEndian(new a() { x = 1 }); + Assert.AreEqual("010000000000000001", key.ToArray().ToHexString()); } } } From 7a06806d84fd36c88a907e9b48fd56d16a6f760f Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 19 Aug 2020 18:35:04 +0800 Subject: [PATCH 17/27] Optimize --- src/neo/SmartContract/Native/KeyBuilder.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/neo/SmartContract/Native/KeyBuilder.cs b/src/neo/SmartContract/Native/KeyBuilder.cs index 0461f87c79..0d6c80970e 100644 --- a/src/neo/SmartContract/Native/KeyBuilder.cs +++ b/src/neo/SmartContract/Native/KeyBuilder.cs @@ -1,9 +1,7 @@ -using Neo.Cryptography; using Neo.IO; using Neo.Ledger; using System; using System.IO; -using System.Linq; namespace Neo.SmartContract.Native { @@ -41,7 +39,10 @@ unsafe public KeyBuilder Add(T key) where T : unmanaged unsafe public KeyBuilder AddBigEndian(T key) where T : unmanaged { - return Add(new ReadOnlySpan(&key, sizeof(T)).ToArray().Reverse().ToArray()); + ReadOnlySpan buffer = new ReadOnlySpan(&key, sizeof(T)); + for (int i = buffer.Length - 1; i >= 0; i--) + stream.WriteByte(buffer[i]); + return this; } public byte[] ToArray() From 548b407bf1561fa3c01419c7a2ce17ac73baa0e7 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Thu, 20 Aug 2020 11:35:12 +0800 Subject: [PATCH 18/27] optimize --- .../SmartContract/Native/Tokens/NeoToken.cs | 84 +++++++++++++------ .../Native/Tokens/UT_GasToken.cs | 2 +- .../Native/Tokens/UT_NeoToken.cs | 2 +- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index f5b84730a1..5ed6fb5e43 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -65,24 +65,24 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta if (value.IsZero || start >= end) return BigInteger.Zero; if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value)); - StorageKey keyLeft = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue - end); - StorageKey keyRight = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue); - var enumerator = snapshot.Storages.FindRange(keyLeft, keyRight).GetEnumerator(); + GasRecord gasRecord = snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); BigInteger sum = 0; uint right = end; - while (enumerator.MoveNext()) + for(var i = gasRecord.Count - 1; i >= 0; i--) { - var gasPerBlock = new BigInteger(enumerator.Current.Value.Value); - var index = uint.MaxValue - BitConverter.ToUInt32(enumerator.Current.Key.Key.Skip(1).Reverse().ToArray()) - 1; - if (index <= start) + var currentIndex = gasRecord[i].Index; + if (currentIndex <= right) { - sum += gasPerBlock * (right - start); - break; - } - else - { - sum += gasPerBlock * (right - index); - right = index; + if (currentIndex > start) + { + sum += gasRecord[i].GasPerBlock * (right - currentIndex); + right = currentIndex; + } + else + { + sum += gasRecord[i].GasPerBlock * (right - start); + break; + } } } return value * sum * NeoHolderRewardRatio / 100 / TotalAmount; @@ -92,10 +92,12 @@ internal override void Initialize(ApplicationEngine engine) { // Initialize economic parameters - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue - 1), new StorageItem - { - Value = (5 * GAS.Factor).ToByteArray() - }); + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock), new StorageItem( + new GasRecord() + { + (0, 5 * GAS.Factor) + } + )); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0])); Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), TotalAmount); @@ -113,20 +115,29 @@ private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) { if (gasPerBlock < 0 || gasPerBlock > 10 * GAS.Factor) return false; if (!CheckCommittee(engine)) return false; - StorageKey key = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue - engine.Snapshot.PersistingBlock.Index - 1); - StorageItem item = engine.Snapshot.Storages.GetAndChange(key, () => new StorageItem { Value = BigInteger.Zero.ToByteArray() }); - item.Value = gasPerBlock.ToByteArray(); + GasRecord gasRecord = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); + if (gasRecord[gasRecord.Count - 1].Index == engine.Snapshot.PersistingBlock.Index) + { + gasRecord[gasRecord.Count - 1] = (engine.Snapshot.PersistingBlock.Index, gasPerBlock); + } + else + { + gasRecord.Add((engine.Snapshot.PersistingBlock.Index, gasPerBlock)); + } return true; } [ContractMethod(0_01000000, CallFlags.AllowStates)] public BigInteger GetGasPerBlock(StoreView snapshot) { - StorageKey keyLeft = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue - snapshot.PersistingBlock.Index - 1); - StorageKey keyRight = CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(uint.MaxValue); - var enumerator = snapshot.Storages.FindRange(keyLeft, keyRight).GetEnumerator(); - enumerator.MoveNext(); - return new BigInteger(enumerator.Current.Value.Value); + var index = snapshot.PersistingBlock.Index; + GasRecord gasRecord = snapshot.Storages.TryGet(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); + for(var i = gasRecord.Count - 1; i >= 0; i--) + { + if (gasRecord[i].Index <= index) + return gasRecord[i].GasPerBlock; + } + return 5 * GAS.Factor; } [ContractMethod(0_03000000, CallFlags.AllowStates)] @@ -292,5 +303,26 @@ public StackItem ToStackItem(ReferenceCounter referenceCounter) return new Struct(referenceCounter) { Registered, Votes }; } } + + internal class GasRecord : List<(uint Index, BigInteger GasPerBlock)>, IInteroperable + { + public void FromStackItem(StackItem stackItem) + { + VM.Types.Array array = (VM.Types.Array)stackItem; + for(var i = 0; i < array.Count; i += 2) + Add(((uint)array[i].GetInteger(), array[i + 1].GetInteger())); + } + + public StackItem ToStackItem(ReferenceCounter referenceCounter) + { + VM.Types.Array array = new VM.Types.Array(); + foreach(var item in this) + { + array.Add(item.Index); + array.Add(item.GasPerBlock); + } + return array; + } + } } } diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 0a25d9973a..9f693777c7 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -70,7 +70,7 @@ public void Check_BalanceOfTransferAndBurn() supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(3000050000000000); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 3); // Gas + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas // Transfer diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 4fae26a467..c55c7b5f5f 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -355,7 +355,7 @@ public void Check_Transfer() unclaim.Value.Should().Be(new BigInteger(0)); unclaim.State.Should().BeTrue(); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + new balance + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 5); // Gas + new balance // Return balance From 75366ed69e7353a5d52864098c1dad34270cd5d3 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Thu, 20 Aug 2020 11:39:16 +0800 Subject: [PATCH 19/27] foramt --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 5ed6fb5e43..5a98597c8b 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -68,7 +68,7 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta GasRecord gasRecord = snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); BigInteger sum = 0; uint right = end; - for(var i = gasRecord.Count - 1; i >= 0; i--) + for (var i = gasRecord.Count - 1; i >= 0; i--) { var currentIndex = gasRecord[i].Index; if (currentIndex <= right) @@ -132,7 +132,7 @@ public BigInteger GetGasPerBlock(StoreView snapshot) { var index = snapshot.PersistingBlock.Index; GasRecord gasRecord = snapshot.Storages.TryGet(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); - for(var i = gasRecord.Count - 1; i >= 0; i--) + for (var i = gasRecord.Count - 1; i >= 0; i--) { if (gasRecord[i].Index <= index) return gasRecord[i].GasPerBlock; @@ -309,14 +309,14 @@ internal class GasRecord : List<(uint Index, BigInteger GasPerBlock)>, IInterope public void FromStackItem(StackItem stackItem) { VM.Types.Array array = (VM.Types.Array)stackItem; - for(var i = 0; i < array.Count; i += 2) + for (var i = 0; i < array.Count; i += 2) Add(((uint)array[i].GetInteger(), array[i + 1].GetInteger())); } public StackItem ToStackItem(ReferenceCounter referenceCounter) { VM.Types.Array array = new VM.Types.Array(); - foreach(var item in this) + foreach (var item in this) { array.Add(item.Index); array.Add(item.GasPerBlock); From 164741a19733a44737eadc0526ff440c40c76801 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 20 Aug 2020 15:08:53 +0800 Subject: [PATCH 20/27] Fix --- .../SmartContract/Native/Tokens/NeoToken.cs | 33 ++++++++----------- .../Native/Tokens/UT_GasToken.cs | 2 +- .../Native/Tokens/UT_NeoToken.cs | 2 +- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 5a98597c8b..ebf1608610 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; +using Array = Neo.VM.Types.Array; namespace Neo.SmartContract.Native.Tokens { @@ -65,7 +66,7 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta if (value.IsZero || start >= end) return BigInteger.Zero; if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value)); - GasRecord gasRecord = snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); + GasRecord gasRecord = snapshot.Storages[CreateStorageKey(Prefix_GasPerBlock)].GetInteroperable(); BigInteger sum = 0; uint right = end; for (var i = gasRecord.Count - 1; i >= 0; i--) @@ -92,12 +93,10 @@ internal override void Initialize(ApplicationEngine engine) { // Initialize economic parameters - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock), new StorageItem( - new GasRecord() - { - (0, 5 * GAS.Factor) - } - )); + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_GasPerBlock), new StorageItem(new GasRecord + { + (0, 5 * GAS.Factor) + })); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0])); Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), TotalAmount); @@ -116,9 +115,9 @@ private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) if (gasPerBlock < 0 || gasPerBlock > 10 * GAS.Factor) return false; if (!CheckCommittee(engine)) return false; GasRecord gasRecord = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); - if (gasRecord[gasRecord.Count - 1].Index == engine.Snapshot.PersistingBlock.Index) + if (gasRecord[^1].Index == engine.Snapshot.PersistingBlock.Index) { - gasRecord[gasRecord.Count - 1] = (engine.Snapshot.PersistingBlock.Index, gasPerBlock); + gasRecord[^1] = (engine.Snapshot.PersistingBlock.Index, gasPerBlock); } else { @@ -308,20 +307,16 @@ internal class GasRecord : List<(uint Index, BigInteger GasPerBlock)>, IInterope { public void FromStackItem(StackItem stackItem) { - VM.Types.Array array = (VM.Types.Array)stackItem; - for (var i = 0; i < array.Count; i += 2) - Add(((uint)array[i].GetInteger(), array[i + 1].GetInteger())); + foreach (StackItem item in (Array)stackItem) + { + Struct @struct = (Struct)item; + Add(((uint)@struct[0].GetInteger(), @struct[1].GetInteger())); + } } public StackItem ToStackItem(ReferenceCounter referenceCounter) { - VM.Types.Array array = new VM.Types.Array(); - foreach (var item in this) - { - array.Add(item.Index); - array.Add(item.GasPerBlock); - } - return array; + return new Array(referenceCounter, this.Select(p => new Struct(referenceCounter, new StackItem[] { p.Index, p.GasPerBlock }))); } } } diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 9f693777c7..0a25d9973a 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -70,7 +70,7 @@ public void Check_BalanceOfTransferAndBurn() supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(3000050000000000); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 3); // Gas // Transfer diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index c55c7b5f5f..4fae26a467 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -355,7 +355,7 @@ public void Check_Transfer() unclaim.Value.Should().Be(new BigInteger(0)); unclaim.State.Should().BeTrue(); - snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 5); // Gas + new balance + snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + new balance // Return balance From b05b8f6448c8bb3b687a4634b91a3d2f173a938e Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 20 Aug 2020 15:24:29 +0800 Subject: [PATCH 21/27] Simplify --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index ebf1608610..dffdff61fa 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -68,20 +68,19 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta GasRecord gasRecord = snapshot.Storages[CreateStorageKey(Prefix_GasPerBlock)].GetInteroperable(); BigInteger sum = 0; - uint right = end; for (var i = gasRecord.Count - 1; i >= 0; i--) { var currentIndex = gasRecord[i].Index; - if (currentIndex <= right) + if (currentIndex <= end) { if (currentIndex > start) { - sum += gasRecord[i].GasPerBlock * (right - currentIndex); - right = currentIndex; + sum += gasRecord[i].GasPerBlock * (end - currentIndex); + end = currentIndex; } else { - sum += gasRecord[i].GasPerBlock * (right - start); + sum += gasRecord[i].GasPerBlock * (end - start); break; } } From 4ac43253f0677aca7f6187005a6cb5b2ee02399e Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 20 Aug 2020 15:30:46 +0800 Subject: [PATCH 22/27] Fix CalculateBonus() --- .../SmartContract/Native/Tokens/NeoToken.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index dffdff61fa..08371a3fbf 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -71,18 +71,16 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta for (var i = gasRecord.Count - 1; i >= 0; i--) { var currentIndex = gasRecord[i].Index; - if (currentIndex <= end) + if (currentIndex >= end) continue; + if (currentIndex > start) { - if (currentIndex > start) - { - sum += gasRecord[i].GasPerBlock * (end - currentIndex); - end = currentIndex; - } - else - { - sum += gasRecord[i].GasPerBlock * (end - start); - break; - } + sum += gasRecord[i].GasPerBlock * (end - currentIndex); + end = currentIndex; + } + else + { + sum += gasRecord[i].GasPerBlock * (end - start); + break; } } return value * sum * NeoHolderRewardRatio / 100 / TotalAmount; From bd56d8470c61151ecef9d2ee1e54ef25e427b02f Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 20 Aug 2020 15:38:10 +0800 Subject: [PATCH 23/27] Throw exception --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 08371a3fbf..ca06d8378c 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -109,7 +109,8 @@ protected override void OnPersist(ApplicationEngine engine) [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) { - if (gasPerBlock < 0 || gasPerBlock > 10 * GAS.Factor) return false; + if (gasPerBlock < 0 || gasPerBlock > 10 * GAS.Factor) + throw new ArgumentOutOfRangeException(nameof(gasPerBlock)); if (!CheckCommittee(engine)) return false; GasRecord gasRecord = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); if (gasRecord[^1].Index == engine.Snapshot.PersistingBlock.Index) From 138b62c5bdcb8bde4fd1d50c8494df9b0dee6536 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 20 Aug 2020 15:40:46 +0800 Subject: [PATCH 24/27] SetGasPerBlock will take effect from the next block. --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index ca06d8378c..da1fe50433 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -112,15 +112,12 @@ private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) if (gasPerBlock < 0 || gasPerBlock > 10 * GAS.Factor) throw new ArgumentOutOfRangeException(nameof(gasPerBlock)); if (!CheckCommittee(engine)) return false; + uint index = engine.Snapshot.PersistingBlock.Index + 1; GasRecord gasRecord = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); - if (gasRecord[^1].Index == engine.Snapshot.PersistingBlock.Index) - { - gasRecord[^1] = (engine.Snapshot.PersistingBlock.Index, gasPerBlock); - } + if (gasRecord[^1].Index == index) + gasRecord[^1] = (index, gasPerBlock); else - { - gasRecord.Add((engine.Snapshot.PersistingBlock.Index, gasPerBlock)); - } + gasRecord.Add((index, gasPerBlock)); return true; } From 66e7eb55b8fd5f92a13ef7f8ace607a8166c041c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 20 Aug 2020 15:44:23 +0800 Subject: [PATCH 25/27] Throw exception in GetGasPerBlock() --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index da1fe50433..452044300b 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -125,13 +125,13 @@ private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) public BigInteger GetGasPerBlock(StoreView snapshot) { var index = snapshot.PersistingBlock.Index; - GasRecord gasRecord = snapshot.Storages.TryGet(CreateStorageKey(Prefix_GasPerBlock)).GetInteroperable(); + GasRecord gasRecord = snapshot.Storages[CreateStorageKey(Prefix_GasPerBlock)].GetInteroperable(); for (var i = gasRecord.Count - 1; i >= 0; i--) { if (gasRecord[i].Index <= index) return gasRecord[i].GasPerBlock; } - return 5 * GAS.Factor; + throw new InvalidOperationException(); } [ContractMethod(0_03000000, CallFlags.AllowStates)] From 4515af83f6c99fdc8c859febd0a8f603b0726d7c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 20 Aug 2020 15:47:06 +0800 Subject: [PATCH 26/27] private --- src/neo/SmartContract/Native/Tokens/NeoToken.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 452044300b..01c3311f8d 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -298,7 +298,7 @@ public StackItem ToStackItem(ReferenceCounter referenceCounter) } } - internal class GasRecord : List<(uint Index, BigInteger GasPerBlock)>, IInteroperable + private sealed class GasRecord : List<(uint Index, BigInteger GasPerBlock)>, IInteroperable { public void FromStackItem(StackItem stackItem) { From 0a38e302e26f9caaf8993b3576e485e84901b84c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 20 Aug 2020 16:27:52 +0800 Subject: [PATCH 27/27] Remove useless code --- src/neo/Ledger/Blockchain.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index c7ce9a412a..0ec0c6ade4 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -30,8 +30,6 @@ internal class PreverifyCompleted { public Transaction Transaction; public Verif public class RelayResult { public IInventory Inventory; public VerifyResult Result; } public static readonly uint MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock; - public const uint DecrementInterval = 2000000; - public static readonly uint[] GenerationAmount = { 6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; public static readonly TimeSpan TimePerBlock = TimeSpan.FromMilliseconds(MillisecondsPerBlock); public static readonly ECPoint[] StandbyCommittee = ProtocolSettings.Default.StandbyCommittee.Select(p => ECPoint.DecodePoint(p.HexToBytes(), ECCurve.Secp256r1)).ToArray(); public static readonly ECPoint[] StandbyValidators = StandbyCommittee[0..ProtocolSettings.Default.ValidatorsCount];