diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 79182f1697..f711268fea 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -377,7 +377,7 @@ public void Reset(byte viewNumber) { PrevHash = Snapshot.CurrentBlockHash, Index = Snapshot.Height + 1, - NextConsensus = Blockchain.GetConsensusAddress(NativeContract.NEO.GetValidators(Snapshot)) + NextConsensus = Blockchain.GetConsensusAddress(NativeContract.NEO.ComputeNextBlockValidators(Snapshot)) }; var pv = Validators; Validators = NativeContract.NEO.GetNextBlockValidators(Snapshot); diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 8c9bdcd7c6..a8e827c11a 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -26,7 +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_Committee = 14; private const byte Prefix_GasPerBlock = 29; private const byte NeoHolderRewardRatio = 10; @@ -91,7 +91,7 @@ private BigInteger CalculateBonus(StoreView snapshot, BigInteger value, uint sta internal override void Initialize(ApplicationEngine engine) { - engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_NextValidators), new StorageItem(Blockchain.StandbyValidators.OrderBy(p => p).ToArray().ToByteArray())); + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_Committee), new StorageItem(Blockchain.StandbyCommittee.ToByteArray())); engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0])); // Initialize economic parameters @@ -109,7 +109,7 @@ protected override void OnPersist(ApplicationEngine engine) base.OnPersist(engine); // Set next validators - engine.Snapshot.Storages[CreateStorageKey(Prefix_NextValidators)].Value = GetValidators(engine.Snapshot).ToByteArray(); + engine.Snapshot.Storages[CreateStorageKey(Prefix_Committee)].Value = ComputeCommitteeMembers(engine.Snapshot).ToArray().ToByteArray(); } protected override void PostPersist(ApplicationEngine engine) @@ -239,16 +239,10 @@ private bool Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) )).Where(p => p.Item2.Registered).Select(p => (p.Item1, p.Item2.Votes)).ToArray(); } - [ContractMethod(1_00000000, CallFlags.AllowStates)] - public ECPoint[] GetValidators(StoreView snapshot) - { - return GetCommitteeMembers(snapshot).Take(ProtocolSettings.Default.ValidatorsCount).OrderBy(p => p).ToArray(); - } - [ContractMethod(1_00000000, CallFlags.AllowStates)] public ECPoint[] GetCommittee(StoreView snapshot) { - return GetCommitteeMembers(snapshot).OrderBy(p => p).ToArray(); + return GetCommitteeFromCache(snapshot).OrderBy(p => p).ToArray(); } public UInt160 GetCommitteeAddress(StoreView snapshot) @@ -257,7 +251,17 @@ public UInt160 GetCommitteeAddress(StoreView snapshot) return Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); } - private IEnumerable GetCommitteeMembers(StoreView snapshot) + private IEnumerable GetCommitteeFromCache(StoreView snapshot) + { + return snapshot.Storages[CreateStorageKey(Prefix_Committee)].GetSerializableList(); + } + + internal ECPoint[] ComputeNextBlockValidators(StoreView snapshot) + { + return ComputeCommitteeMembers(snapshot).Take(ProtocolSettings.Default.ValidatorsCount).OrderBy(p => p).ToArray(); + } + + private IEnumerable ComputeCommitteeMembers(StoreView snapshot) { decimal votersCount = (decimal)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_VotersCount)]; decimal VoterTurnout = votersCount / (decimal)TotalAmount; @@ -272,7 +276,10 @@ private IEnumerable GetCommitteeMembers(StoreView snapshot) [ContractMethod(1_00000000, CallFlags.AllowStates)] public ECPoint[] GetNextBlockValidators(StoreView snapshot) { - return snapshot.Storages[CreateStorageKey(Prefix_NextValidators)].GetSerializableList().ToArray(); + return GetCommitteeFromCache(snapshot) + .Take(ProtocolSettings.Default.ValidatorsCount) + .OrderBy(p => p) + .ToArray(); } public class NeoAccountState : AccountState diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index da8acd3dda..e7ce88be40 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -56,7 +56,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm UT_Crypto.generateKey(32), UT_Crypto.generateKey(32), UT_Crypto.generateKey(32) - }; + }.OrderBy(p => p.PublicKey).ToArray(); var timeValues = new[] { new DateTime(1980, 06, 01, 0, 0, 1, 001, DateTimeKind.Utc), // For tests, used below @@ -414,7 +414,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("mockContext Reset for returning Blockchain.Singleton snapshot to original state."); mockContext.Object.Reset(0); mockContext.Object.Snapshot.Storages.Delete(CreateStorageKeyForNativeNeo(14)); - mockContext.Object.Snapshot.Storages.Add(CreateStorageKeyForNativeNeo(14), new StorageItem(Blockchain.StandbyValidators.OrderBy(p => p).ToArray().ToByteArray())); + mockContext.Object.Snapshot.Storages.Add(CreateStorageKeyForNativeNeo(14), new StorageItem(Blockchain.StandbyCommittee.ToByteArray())); mockContext.Object.Snapshot.Commit(); Console.WriteLine("mockContext Reset."); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 2ab695a19a..369dcd007c 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -314,6 +314,18 @@ public void Check_GetCommittee() Check_RegisterValidator(snapshot, Blockchain.StandbyCommittee[i].ToArray()); var currentCandidates = NativeContract.NEO.GetCandidates(snapshot); } + + Script onPersistScript; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitAppCall(NativeContract.NEO.Hash, "onPersist"); + sb.Emit(OpCode.DROP); + onPersistScript = sb.ToArray(); + } + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.System, null, snapshot); + engine.LoadScript(onPersistScript); + Assert.AreEqual(engine.Execute(), VMState.HALT); + committeemembers = NativeContract.NEO.GetCommittee(snapshot); committeemembers.Length.Should().Be(ProtocolSettings.Default.CommitteeMembersCount); committeemembers.Contains(ECCurve.Secp256r1.G).Should().BeTrue(); @@ -418,7 +430,7 @@ public void Check_Initialize() // StandbyValidators - Check_GetValidators(snapshot); + Check_GetCommittee(snapshot); } [TestMethod] @@ -525,28 +537,42 @@ public void TestGetCandidates2() } [TestMethod] - public void TestGetValidators1() + public void TestGetCommittee() { - using (ApplicationEngine engine = NativeContract.NEO.TestCall("getValidators")) + using (ApplicationEngine engine = NativeContract.NEO.TestCall("getCommittee")) { var result = engine.ResultStack.Peek(); result.GetType().Should().Be(typeof(VM.Types.Array)); - ((VM.Types.Array)result).Count.Should().Be(7); - ((VM.Types.Array)result)[0].GetSpan().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); - ((VM.Types.Array)result)[1].GetSpan().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); - ((VM.Types.Array)result)[2].GetSpan().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); - ((VM.Types.Array)result)[3].GetSpan().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); - ((VM.Types.Array)result)[4].GetSpan().ToHexString().Should().Be("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"); - ((VM.Types.Array)result)[5].GetSpan().ToHexString().Should().Be("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"); - ((VM.Types.Array)result)[6].GetSpan().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); + ((VM.Types.Array)result).Count.Should().Be(21); + ((VM.Types.Array)result)[0].GetSpan().ToHexString().Should().Be("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639"); + ((VM.Types.Array)result)[1].GetSpan().ToHexString().Should().Be("03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0"); + ((VM.Types.Array)result)[2].GetSpan().ToHexString().Should().Be("0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30"); + ((VM.Types.Array)result)[3].GetSpan().ToHexString().Should().Be("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d"); + ((VM.Types.Array)result)[4].GetSpan().ToHexString().Should().Be("023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe"); + ((VM.Types.Array)result)[5].GetSpan().ToHexString().Should().Be("03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0"); + ((VM.Types.Array)result)[6].GetSpan().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); + ((VM.Types.Array)result)[7].GetSpan().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); + ((VM.Types.Array)result)[8].GetSpan().ToHexString().Should().Be("02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad"); + ((VM.Types.Array)result)[9].GetSpan().ToHexString().Should().Be("03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379"); + ((VM.Types.Array)result)[10].GetSpan().ToHexString().Should().Be("0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654"); + ((VM.Types.Array)result)[11].GetSpan().ToHexString().Should().Be("02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62"); + ((VM.Types.Array)result)[12].GetSpan().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); + ((VM.Types.Array)result)[13].GetSpan().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); + ((VM.Types.Array)result)[14].GetSpan().ToHexString().Should().Be("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"); + ((VM.Types.Array)result)[15].GetSpan().ToHexString().Should().Be("03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050"); + ((VM.Types.Array)result)[16].GetSpan().ToHexString().Should().Be("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"); + ((VM.Types.Array)result)[17].GetSpan().ToHexString().Should().Be("02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a"); + ((VM.Types.Array)result)[18].GetSpan().ToHexString().Should().Be("03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc"); + ((VM.Types.Array)result)[19].GetSpan().ToHexString().Should().Be("03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde"); + ((VM.Types.Array)result)[20].GetSpan().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); } } [TestMethod] - public void TestGetValidators2() + public void TestGetValidators() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var result = NativeContract.NEO.GetValidators(snapshot); + var result = NativeContract.NEO.ComputeNextBlockValidators(snapshot); result[0].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); result[1].ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); result[2].ToArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); @@ -771,7 +797,7 @@ internal static (bool State, bool Result) Check_RegisterValidator(StoreView snap return (true, result.GetBoolean()); } - internal static ECPoint[] Check_GetValidators(StoreView snapshot) + internal static ECPoint[] Check_GetCommittee(StoreView snapshot) { var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); @@ -780,7 +806,7 @@ internal static ECPoint[] Check_GetValidators(StoreView snapshot) var script = new ScriptBuilder(); script.EmitPush(0); script.Emit(OpCode.PACK); - script.EmitPush("getValidators"); + script.EmitPush("getCommittee"); engine.LoadScript(script.ToArray()); engine.Execute().Should().Be(VMState.HALT);