Skip to content

Commit

Permalink
Cache committee in storage (#1920)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikzhang committed Sep 10, 2020
1 parent c5ce4c9 commit cf206c8
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 30 deletions.
2 changes: 1 addition & 1 deletion src/neo/Consensus/ConsensusContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 19 additions & 12 deletions src/neo/SmartContract/Native/Tokens/NeoToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public sealed class NeoToken : Nep5Token<NeoToken.NeoAccountState>

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;
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -257,7 +251,17 @@ public UInt160 GetCommitteeAddress(StoreView snapshot)
return Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash();
}

private IEnumerable<ECPoint> GetCommitteeMembers(StoreView snapshot)
private IEnumerable<ECPoint> GetCommitteeFromCache(StoreView snapshot)
{
return snapshot.Storages[CreateStorageKey(Prefix_Committee)].GetSerializableList<ECPoint>();
}

internal ECPoint[] ComputeNextBlockValidators(StoreView snapshot)
{
return ComputeCommitteeMembers(snapshot).Take(ProtocolSettings.Default.ValidatorsCount).OrderBy(p => p).ToArray();
}

private IEnumerable<ECPoint> ComputeCommitteeMembers(StoreView snapshot)
{
decimal votersCount = (decimal)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_VotersCount)];
decimal VoterTurnout = votersCount / (decimal)TotalAmount;
Expand All @@ -272,7 +276,10 @@ private IEnumerable<ECPoint> GetCommitteeMembers(StoreView snapshot)
[ContractMethod(1_00000000, CallFlags.AllowStates)]
public ECPoint[] GetNextBlockValidators(StoreView snapshot)
{
return snapshot.Storages[CreateStorageKey(Prefix_NextValidators)].GetSerializableList<ECPoint>().ToArray();
return GetCommitteeFromCache(snapshot)
.Take(ProtocolSettings.Default.ValidatorsCount)
.OrderBy(p => p)
.ToArray();
}

public class NeoAccountState : AccountState
Expand Down
4 changes: 2 additions & 2 deletions tests/neo.UnitTests/Consensus/UT_Consensus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.");
Expand Down
56 changes: 41 additions & 15 deletions tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -418,7 +430,7 @@ public void Check_Initialize()

// StandbyValidators

Check_GetValidators(snapshot);
Check_GetCommittee(snapshot);
}

[TestMethod]
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand Down

0 comments on commit cf206c8

Please sign in to comment.