diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 17fc28c0ad..552227f7be 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -38,11 +38,10 @@ internal bool CheckPolicy(Transaction tx, StoreView snapshot) return true; } - private bool CheckValidators(ApplicationEngine engine) + private bool CheckCommittees(ApplicationEngine engine) { - UInt256 prev_hash = engine.Snapshot.PersistingBlock.PrevHash; - TrimmedBlock prev_block = engine.Snapshot.Blocks[prev_hash]; - return InteropService.Runtime.CheckWitnessInternal(engine, prev_block.NextConsensus); + UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); + return InteropService.Runtime.CheckWitnessInternal(engine, committeeMultiSigAddr); } internal override bool Initialize(ApplicationEngine engine) @@ -114,7 +113,7 @@ public UInt160[] GetBlockedAccounts(StoreView snapshot) [ContractMethod(0_03000000, ContractParameterType.Boolean, CallFlags.AllowModifyStates, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "value" })] private StackItem SetMaxBlockSize(ApplicationEngine engine, Array args) { - if (!CheckValidators(engine)) return false; + if (!CheckCommittees(engine)) return false; uint value = (uint)args[0].GetBigInteger(); if (Network.P2P.Message.PayloadMaxSize <= value) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSize)); @@ -125,7 +124,7 @@ private StackItem SetMaxBlockSize(ApplicationEngine engine, Array args) [ContractMethod(0_03000000, ContractParameterType.Boolean, CallFlags.AllowModifyStates, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "value" })] private StackItem SetMaxTransactionsPerBlock(ApplicationEngine engine, Array args) { - if (!CheckValidators(engine)) return false; + if (!CheckCommittees(engine)) return false; uint value = (uint)args[0].GetBigInteger(); StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxTransactionsPerBlock)); storage.Value = BitConverter.GetBytes(value); @@ -135,7 +134,7 @@ private StackItem SetMaxTransactionsPerBlock(ApplicationEngine engine, Array arg [ContractMethod(0_03000000, ContractParameterType.Boolean, CallFlags.AllowModifyStates, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "value" })] private StackItem SetFeePerByte(ApplicationEngine engine, Array args) { - if (!CheckValidators(engine)) return false; + if (!CheckCommittees(engine)) return false; long value = (long)args[0].GetBigInteger(); StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_FeePerByte)); storage.Value = BitConverter.GetBytes(value); @@ -145,7 +144,7 @@ private StackItem SetFeePerByte(ApplicationEngine engine, Array args) [ContractMethod(0_03000000, ContractParameterType.Boolean, CallFlags.AllowModifyStates, ParameterTypes = new[] { ContractParameterType.Hash160 }, ParameterNames = new[] { "account" })] private StackItem BlockAccount(ApplicationEngine engine, Array args) { - if (!CheckValidators(engine)) return false; + if (!CheckCommittees(engine)) return false; UInt160 account = new UInt160(args[0].GetSpan()); StorageKey key = CreateStorageKey(Prefix_BlockedAccounts); StorageItem storage = engine.Snapshot.Storages[key]; @@ -159,7 +158,7 @@ private StackItem BlockAccount(ApplicationEngine engine, Array args) [ContractMethod(0_03000000, ContractParameterType.Boolean, CallFlags.AllowModifyStates, ParameterTypes = new[] { ContractParameterType.Hash160 }, ParameterNames = new[] { "account" })] private StackItem UnblockAccount(ApplicationEngine engine, Array args) { - if (!CheckValidators(engine)) return false; + if (!CheckCommittees(engine)) return false; UInt160 account = new UInt160(args[0].GetSpan()); StorageKey key = CreateStorageKey(Prefix_BlockedAccounts); StorageItem storage = engine.Snapshot.Storages[key]; diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 67e6260eee..3793765c12 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -246,6 +246,12 @@ public ECPoint[] GetCommittee(StoreView snapshot) return GetCommitteeMembers(snapshot, ProtocolSettings.Default.MaxCommitteeMembersCount).OrderBy(p => p).ToArray(); } + public UInt160 GetCommitteeAddress(StoreView snapshot) + { + ECPoint[] committees = GetCommittee(snapshot); + return Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); + } + private IEnumerable GetCommitteeMembers(StoreView snapshot, int count) { return GetCandidates(snapshot).OrderByDescending(p => p.Votes).ThenBy(p => p.PublicKey).Select(p => p.PublicKey).Take(count); diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index a173585182..22442e08cf 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -61,6 +61,8 @@ public void Check_SetMaxBlockSize() snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); + UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); + NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue(); // Without signature @@ -76,7 +78,7 @@ public void Check_SetMaxBlockSize() // More than expected - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero), + ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = Neo.Network.P2P.Message.PayloadMaxSize }); ret.Should().BeOfType(); ret.ToBoolean().Should().BeFalse(); @@ -87,7 +89,7 @@ public void Check_SetMaxBlockSize() // With signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero), + ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 }); ret.Should().BeOfType(); ret.ToBoolean().Should().BeTrue(); @@ -122,7 +124,7 @@ public void Check_SetMaxTransactionsPerBlock() // With signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero), + ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(NativeContract.NEO.GetCommitteeAddress(snapshot)), "setMaxTransactionsPerBlock", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); ret.ToBoolean().Should().BeTrue(); @@ -156,8 +158,8 @@ public void Check_SetFeePerByte() ret.GetBigInteger().Should().Be(1000); // With signature - - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero), + UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); + ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setFeePerByte", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); ret.ToBoolean().Should().BeTrue(); @@ -177,6 +179,8 @@ public void Check_Block_UnblockAccount() snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); + UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); + NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)).Should().BeTrue(); // Block without signature @@ -192,7 +196,7 @@ public void Check_Block_UnblockAccount() // Block with signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero), + ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "blockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); ret.ToBoolean().Should().BeTrue(); @@ -216,7 +220,7 @@ public void Check_Block_UnblockAccount() // Unblock with signature - ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(UInt160.Zero), + ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "unblockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); ret.ToBoolean().Should().BeTrue();