Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EffectiveVoterTurnout #1762

Merged
merged 3 commits into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/neo/Consensus/ConsensusContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ public void Deserialize(BinaryReader reader)
ViewNumber = reader.ReadByte();
TransactionHashes = reader.ReadSerializableArray<UInt256>();
Transaction[] transactions = reader.ReadSerializableArray<Transaction>(Block.MaxTransactionsPerBlock);
PreparationPayloads = reader.ReadNullableArray<ConsensusPayload>(ProtocolSettings.Default.MaxValidatorsCount);
CommitPayloads = reader.ReadNullableArray<ConsensusPayload>(ProtocolSettings.Default.MaxValidatorsCount);
ChangeViewPayloads = reader.ReadNullableArray<ConsensusPayload>(ProtocolSettings.Default.MaxValidatorsCount);
LastChangeViewPayloads = reader.ReadNullableArray<ConsensusPayload>(ProtocolSettings.Default.MaxValidatorsCount);
PreparationPayloads = reader.ReadNullableArray<ConsensusPayload>(ProtocolSettings.Default.ValidatorsCount);
CommitPayloads = reader.ReadNullableArray<ConsensusPayload>(ProtocolSettings.Default.ValidatorsCount);
ChangeViewPayloads = reader.ReadNullableArray<ConsensusPayload>(ProtocolSettings.Default.ValidatorsCount);
LastChangeViewPayloads = reader.ReadNullableArray<ConsensusPayload>(ProtocolSettings.Default.ValidatorsCount);
if (TransactionHashes.Length == 0 && !RequestSentOrReceived)
TransactionHashes = null;
Transactions = transactions.Length == 0 && !RequestSentOrReceived ? null : transactions.ToDictionary(p => p.Hash);
Expand Down
6 changes: 3 additions & 3 deletions src/neo/Consensus/RecoveryMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public RecoveryMessage() : base(ConsensusMessageType.RecoveryMessage)
public override void Deserialize(BinaryReader reader)
{
base.Deserialize(reader);
ChangeViewMessages = reader.ReadSerializableArray<ChangeViewPayloadCompact>(ProtocolSettings.Default.MaxValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex);
ChangeViewMessages = reader.ReadSerializableArray<ChangeViewPayloadCompact>(ProtocolSettings.Default.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex);
if (reader.ReadBoolean())
PrepareRequestMessage = reader.ReadSerializable<PrepareRequest>();
else
Expand All @@ -41,8 +41,8 @@ public override void Deserialize(BinaryReader reader)
PreparationHash = new UInt256(reader.ReadFixedBytes(preparationHashSize));
}

PreparationMessages = reader.ReadSerializableArray<PreparationPayloadCompact>(ProtocolSettings.Default.MaxValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex);
CommitMessages = reader.ReadSerializableArray<CommitPayloadCompact>(ProtocolSettings.Default.MaxValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex);
PreparationMessages = reader.ReadSerializableArray<PreparationPayloadCompact>(ProtocolSettings.Default.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex);
CommitMessages = reader.ReadSerializableArray<CommitPayloadCompact>(ProtocolSettings.Default.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex);
}

internal ConsensusPayload[] GetChangeViewPayloads(ConsensusContext context, ConsensusPayload payload)
Expand Down
4 changes: 2 additions & 2 deletions src/neo/Ledger/Blockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu
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.Take(ProtocolSettings.Default.MaxCommitteeMembersCount).Select(p => ECPoint.DecodePoint(p.HexToBytes(), ECCurve.Secp256r1)).ToArray();
public static readonly ECPoint[] StandbyValidators = StandbyCommittee.Take(ProtocolSettings.Default.MaxValidatorsCount).ToArray();
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];

public static readonly Block GenesisBlock = new Block
{
Expand Down
2 changes: 1 addition & 1 deletion src/neo/Network/P2P/Payloads/ConsensusData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public UInt256 Hash

void ISerializable.Deserialize(BinaryReader reader)
{
PrimaryIndex = (uint)reader.ReadVarInt((ulong)ProtocolSettings.Default.MaxValidatorsCount - 1);
PrimaryIndex = (uint)reader.ReadVarInt((ulong)ProtocolSettings.Default.ValidatorsCount - 1);
Nonce = reader.ReadUInt64();
}

Expand Down
8 changes: 4 additions & 4 deletions src/neo/ProtocolSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public class ProtocolSettings
public uint Magic { get; }
public byte AddressVersion { get; }
public string[] StandbyCommittee { get; }
public byte MaxCommitteeMembersCount { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who currently can edit these values MaxCommitteeMembersCount and MaxValidatorsCount?
They are set by default, right, on the protocol?
Perhaps we need also the Committee to vote for these values onchain, at least.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No one can edit these values. They are hard-coded.

public byte MaxValidatorsCount { get; }
public int CommitteeMembersCount { get; }
vncoelho marked this conversation as resolved.
Show resolved Hide resolved
public int ValidatorsCount { get; }
public string[] SeedList { get; }
public uint MillisecondsPerBlock { get; }
public int MemoryPoolMaxTransactions { get; }
Expand Down Expand Up @@ -78,8 +78,8 @@ private ProtocolSettings(IConfigurationSection section)
"03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc",
"02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a"
};
this.MaxCommitteeMembersCount = section.GetValue("MaxCommitteeMembersCount", (byte)21);
this.MaxValidatorsCount = section.GetValue("MaxValidatorsCount", (byte)7);
this.CommitteeMembersCount = StandbyCommittee.Length;
this.ValidatorsCount = section.GetValue("ValidatorsCount", (byte)7);
IConfigurationSection section_sl = section.GetSection("SeedList");
if (section_sl.Exists())
this.SeedList = section_sl.GetChildren().Select(p => p.Get<string>()).ToArray();
Expand Down
8 changes: 8 additions & 0 deletions src/neo/SmartContract/Native/KeyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ unsafe public KeyBuilder Add<T>(T key) where T : unmanaged
return Add(new ReadOnlySpan<byte>(&key, sizeof(T)));
}

public byte[] ToArray()
{
using (stream)
{
return StorageKey.CreateSearchPrefix(id, stream.ToArray());
}
}

public static implicit operator StorageKey(KeyBuilder builder)
{
using (builder.stream)
Expand Down
85 changes: 40 additions & 45 deletions src/neo/SmartContract/Native/Tokens/NeoToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public sealed class NeoToken : Nep5Token<NeoToken.NeoAccountState>
public override byte Decimals => 0;
public BigInteger TotalAmount { get; }

public const decimal EffectiveVoterTurnout = 0.2M;

private const byte Prefix_VotersCount = 1;
private const byte Prefix_Candidate = 33;
private const byte Prefix_NextValidators = 14;

Expand All @@ -40,9 +43,10 @@ protected override void OnBalanceChanging(ApplicationEngine engine, UInt160 acco
if (amount.IsZero) return;
if (state.VoteTo != null)
{
StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(state.VoteTo));
CandidateState state_validator = storage_validator.GetInteroperable<CandidateState>();
state_validator.Votes += amount;
engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(state.VoteTo)).GetInteroperable<CandidateState>().Votes += amount;
StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount));
BigInteger votersCount = new BigInteger(item.Value) + amount;
item.Value = votersCount.ToByteArray();
}
}

Expand Down Expand Up @@ -87,19 +91,8 @@ private BigInteger CalculateBonus(BigInteger value, uint start, uint end)

internal override void Initialize(ApplicationEngine engine)
{
BigInteger amount = TotalAmount;
for (int i = 0; i < Blockchain.StandbyCommittee.Length; i++)
{
ECPoint pubkey = Blockchain.StandbyCommittee[i];
RegisterCandidateInternal(engine.Snapshot, pubkey);
BigInteger balance = TotalAmount / 2 / (Blockchain.StandbyValidators.Length * 2 + (Blockchain.StandbyCommittee.Length - Blockchain.StandbyValidators.Length));
if (i < Blockchain.StandbyValidators.Length) balance *= 2;
UInt160 account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash();
Mint(engine, account, balance);
VoteInternal(engine.Snapshot, account, pubkey);
amount -= balance;
}
Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), amount);
engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0]));
shargon marked this conversation as resolved.
Show resolved Hide resolved
Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), TotalAmount);
}

protected override void OnPersist(ApplicationEngine engine)
Expand All @@ -123,16 +116,11 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey)
{
if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash()))
return false;
RegisterCandidateInternal(engine.Snapshot, pubkey);
return true;
}

private void RegisterCandidateInternal(StoreView snapshot, ECPoint pubkey)
{
StorageKey key = CreateStorageKey(Prefix_Candidate).Add(pubkey);
StorageItem item = snapshot.Storages.GetAndChange(key, () => new StorageItem(new CandidateState()));
StorageItem item = engine.Snapshot.Storages.GetAndChange(key, () => new StorageItem(new CandidateState()));
CandidateState state = item.GetInteroperable<CandidateState>();
state.Registered = true;
return true;
}

[ContractMethod(0_05000000, CallFlags.AllowModifyStates)]
Expand All @@ -155,30 +143,35 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey)
private bool Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo)
{
if (!engine.CheckWitnessInternal(account)) return false;
return VoteInternal(engine.Snapshot, account, voteTo);
}

private bool VoteInternal(StoreView snapshot, UInt160 account, ECPoint voteTo)
{
StorageKey key_account = CreateStorageKey(Prefix_Account).Add(account);
if (snapshot.Storages.TryGet(key_account) is null) return false;
StorageItem storage_account = snapshot.Storages.GetAndChange(key_account);
if (engine.Snapshot.Storages.TryGet(key_account) is null) return false;
StorageItem storage_account = engine.Snapshot.Storages.GetAndChange(key_account);
NeoAccountState state_account = storage_account.GetInteroperable<NeoAccountState>();
if (state_account.VoteTo is null ^ voteTo is null)
shargon marked this conversation as resolved.
Show resolved Hide resolved
{
StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount));
BigInteger votersCount = new BigInteger(item.Value);
if (state_account.VoteTo is null)
votersCount += state_account.Balance;
else
votersCount -= state_account.Balance;
item.Value = votersCount.ToByteArray();
}
if (state_account.VoteTo != null)
{
StorageKey key = CreateStorageKey(Prefix_Candidate).Add(state_account.VoteTo);
StorageItem storage_validator = snapshot.Storages.GetAndChange(key);
StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(key);
CandidateState state_validator = storage_validator.GetInteroperable<CandidateState>();
state_validator.Votes -= state_account.Balance;
if (!state_validator.Registered && state_validator.Votes.IsZero)
snapshot.Storages.Delete(key);
engine.Snapshot.Storages.Delete(key);
}
state_account.VoteTo = voteTo;
if (voteTo != null)
{
StorageKey key = CreateStorageKey(Prefix_Candidate).Add(voteTo);
if (snapshot.Storages.TryGet(key) is null) return false;
StorageItem storage_validator = snapshot.Storages.GetAndChange(key);
if (engine.Snapshot.Storages.TryGet(key) is null) return false;
StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(key);
CandidateState state_validator = storage_validator.GetInteroperable<CandidateState>();
if (!state_validator.Registered) return false;
state_validator.Votes += state_account.Balance;
Expand All @@ -189,29 +182,24 @@ private bool VoteInternal(StoreView snapshot, UInt160 account, ECPoint voteTo)
[ContractMethod(1_00000000, CallFlags.AllowStates)]
public (ECPoint PublicKey, BigInteger Votes)[] GetCandidates(StoreView snapshot)
{
return GetCandidatesInternal(snapshot).ToArray();
}

private IEnumerable<(ECPoint PublicKey, BigInteger Votes)> GetCandidatesInternal(StoreView snapshot)
{
byte[] prefix_key = StorageKey.CreateSearchPrefix(Id, new[] { Prefix_Candidate });
byte[] prefix_key = CreateStorageKey(Prefix_Candidate).ToArray();
return snapshot.Storages.Find(prefix_key).Select(p =>
(
p.Key.Key.AsSerializable<ECPoint>(1),
p.Value.GetInteroperable<CandidateState>()
)).Where(p => p.Item2.Registered).Select(p => (p.Item1, p.Item2.Votes));
)).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, ProtocolSettings.Default.MaxValidatorsCount).OrderBy(p => p).ToArray();
return GetCommitteeMembers(snapshot).Take(ProtocolSettings.Default.ValidatorsCount).OrderBy(p => p).ToArray();
}

[ContractMethod(1_00000000, CallFlags.AllowStates)]
public ECPoint[] GetCommittee(StoreView snapshot)
{
return GetCommitteeMembers(snapshot, ProtocolSettings.Default.MaxCommitteeMembersCount).OrderBy(p => p).ToArray();
return GetCommitteeMembers(snapshot).OrderBy(p => p).ToArray();
}

public UInt160 GetCommitteeAddress(StoreView snapshot)
Expand All @@ -220,9 +208,16 @@ public UInt160 GetCommitteeAddress(StoreView snapshot)
return Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash();
}

private IEnumerable<ECPoint> GetCommitteeMembers(StoreView snapshot, int count)
private IEnumerable<ECPoint> GetCommitteeMembers(StoreView snapshot)
{
return GetCandidatesInternal(snapshot).OrderByDescending(p => p.Votes).ThenBy(p => p.PublicKey).Select(p => p.PublicKey).Take(count);
decimal votersCount = (decimal)new BigInteger(snapshot.Storages[CreateStorageKey(Prefix_VotersCount)].Value);
decimal VoterTurnout = votersCount / (decimal)TotalAmount;
if (VoterTurnout < EffectiveVoterTurnout)
return Blockchain.StandbyCommittee;
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
var candidates = GetCandidates(snapshot);
if (candidates.Length < ProtocolSettings.Default.CommitteeMembersCount)
return Blockchain.StandbyCommittee;
return candidates.OrderByDescending(p => p.Votes).ThenBy(p => p.PublicKey).Select(p => p.PublicKey).Take(ProtocolSettings.Default.CommitteeMembersCount);
}

[ContractMethod(1_00000000, CallFlags.AllowStates)]
Expand Down
22 changes: 11 additions & 11 deletions tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,16 @@ public void Check_BalanceOfTransferAndBurn()
// Check unclaim

var unclaim = UT_NeoToken.Check_UnclaimedGas(snapshot, from);
unclaim.Value.Should().Be(new BigInteger(300000048000));
unclaim.Value.Should().Be(new BigInteger(600000000000));
unclaim.State.Should().BeTrue();

// Transfer

NativeContract.NEO.Transfer(snapshot, from, to, BigInteger.Zero, true).Should().BeTrue();
NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(50000008);
NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(100000000);
NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(0);

NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(3000300000048000);
NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(30006000_00000000);
NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(0);

// Check unclaim
Expand All @@ -68,21 +68,21 @@ public void Check_BalanceOfTransferAndBurn()
unclaim.State.Should().BeTrue();

supply = NativeContract.GAS.TotalSupply(snapshot);
supply.Should().Be(3000300000048000);
supply.Should().Be(30006000_00000000);

snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 3); // Gas

// Transfer

keyCount = snapshot.Storages.GetChangeSet().Count();

NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048000, false).Should().BeFalse(); // Not signed
NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048001, true).Should().BeFalse(); // More than balance
NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048000, true).Should().BeTrue(); // All balance
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

// Balance of

NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000300000048000);
NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30006000_00000000);
NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(0);

snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 1); // All
Expand All @@ -98,19 +98,19 @@ public void Check_BalanceOfTransferAndBurn()
// Burn more than expected

Assert.ThrowsException<InvalidOperationException>(() =>
NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000300000048001)));
NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(30006000_00000001)));

// Real burn

NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(1));

NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000300000047999);
NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30005999_99999999);

keyCount.Should().Be(snapshot.Storages.GetChangeSet().Count());

// Burn all

NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000300000047999));
NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(30005999_99999999));

(keyCount - 1).Should().Be(snapshot.Storages.GetChangeSet().Count());

Expand Down
Loading