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 Economic Model #1716

Closed
wants to merge 53 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
380efa4
add economic model
Jun 20, 2020
43d0139
Merge remote-tracking branch 'upstream/master' into add_economic_model
Jun 22, 2020
8644dbb
fix
Jun 23, 2020
29d21ac
fix ut
Jun 23, 2020
d7e212f
add mark
Jun 23, 2020
397897f
fix consensus_ut
Jun 24, 2020
8d31450
add ut
Jun 28, 2020
9c09c1d
merge
Jun 28, 2020
7bdbc4f
format
Jun 28, 2020
74f9a19
fix ut
Jun 28, 2020
64ede76
fix
Jun 28, 2020
23aa3c5
fix ut
Jun 28, 2020
88e57b7
apply recommedations
Jun 29, 2020
28d5186
Merge branch 'master' into add_economic_model
shargon Jun 29, 2020
0950567
optimize reward ratio
Jun 30, 2020
8a04041
Merge branch 'add_economic_model' of https://github.com/Tommo-L/neo i…
Jun 30, 2020
4b854e1
reset datacache
Jul 3, 2020
4e767df
Merge remote-tracking branch 'upstream/master' into add_economic_model
Jul 3, 2020
3e849f0
reset datacache
Jul 3, 2020
0b5b29a
Update src/neo/SmartContract/Native/NativeContract.cs
shargon Jul 3, 2020
c24a6e9
Merge branch 'master' into add_economic_model
erikzhang Jul 3, 2020
feb6d36
apply recommendations
Jul 3, 2020
ce7a5b1
optimize createstoragekey
Jul 5, 2020
ada8c2f
KeyBuilder.ToArray()
erikzhang Jul 6, 2020
92fa72a
Disable warning
erikzhang Jul 6, 2020
85b2a74
Merge branch 'master' into add_economic_model
shargon Jul 10, 2020
70a6291
Add blank line
shargon Jul 10, 2020
7019a0a
optimize
Jul 10, 2020
f68f5a6
resolve
Jul 10, 2020
f2d25e9
format
Jul 10, 2020
a053d2f
format
Jul 10, 2020
3860cc4
format
Jul 10, 2020
9408a11
Merge branch 'master' into add_economic_model
shargon Jul 11, 2020
eef1582
Merge branch 'master' into add_economic_model
shargon Jul 13, 2020
255382f
Merge branch 'master' into add_economic_model
erikzhang Jul 14, 2020
033205c
Fix UT
erikzhang Jul 14, 2020
3d5df3e
fix conflicts
Jul 15, 2020
ee5e874
format
Jul 15, 2020
649be9f
Merge branch 'master' into add_economic_model
shargon Jul 16, 2020
32db697
fix vote
Jul 16, 2020
66db3ea
Merge branch 'add_economic_model' of https://github.com/Tommo-L/neo i…
Jul 16, 2020
2e24381
fix conflicts
Jul 27, 2020
a2a372f
fix ut later
Jul 28, 2020
b6da509
resolve
Aug 6, 2020
5465f4d
fix ut
Aug 6, 2020
5ece87f
Change to pubKey
shargon Aug 7, 2020
f035479
Merge remote-tracking branch 'neo-project/master' into add_economic_m…
shargon Aug 7, 2020
96f8891
Fix Merge
shargon Aug 7, 2020
174e3f0
Fix merge
shargon Aug 7, 2020
17b0d05
Fix keys
shargon Aug 7, 2020
d851966
combine economic & governance
Aug 11, 2020
a6198d5
Fix null
shargon Aug 11, 2020
c44d7df
Merge branch 'master' into add_economic_model
erikzhang Aug 16, 2020
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
6 changes: 3 additions & 3 deletions src/neo/IO/Caching/CloneCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ protected override void DeleteInternal(TKey key)
innerCache.Delete(key);
}

protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix)
protected override IEnumerable<(TKey, TValue)> SeekInternal(byte[] key)
{
foreach (var (key, value) in innerCache.Find(key_prefix))
yield return (key, value.Clone());
foreach (var (ikey, ivalue) in innerCache.Seek(key))
yield return (ikey, ivalue.Clone());
}

protected override TValue GetInternal(TKey key)
Expand Down
36 changes: 27 additions & 9 deletions src/neo/IO/Caching/DataCache.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.EntityFrameworkCore.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -144,19 +145,14 @@ public void Delete(TKey key)

protected abstract void DeleteInternal(TKey key);

/// <summary>
/// Find the entries that start with the `key_prefix`
/// </summary>
/// <param name="key_prefix">Must maintain the deserialized format of TKey</param>
/// <returns>Entries found with the desired prefix</returns>
public IEnumerable<(TKey Key, TValue Value)> Find(byte[] key_prefix = null)
public IEnumerable<(TKey key, TValue value)> Seek(byte[] key)
{
IEnumerable<(byte[], TKey, TValue)> cached;
HashSet<TKey> cachedKeySet;
lock (dictionary)
{
cached = dictionary
.Where(p => p.Value.State != TrackState.Deleted && (key_prefix == null || p.Key.ToArray().AsSpan().StartsWith(key_prefix)))
.Where(p => p.Value.State != TrackState.Deleted && (key == null || ByteArrayComparer.Default.Compare(p.Key.ToArray(), key) >= 0))
.Select(p =>
(
KeyBytes: p.Key.ToArray(),
Expand All @@ -167,7 +163,7 @@ public void Delete(TKey key)
.ToArray();
cachedKeySet = new HashSet<TKey>(dictionary.Keys);
}
var uncached = FindInternal(key_prefix ?? Array.Empty<byte>())
var uncached = SeekInternal(key ?? Array.Empty<byte>())
.Where(p => !cachedKeySet.Contains(p.Key))
.Select(p =>
(
Expand Down Expand Up @@ -201,7 +197,29 @@ public void Delete(TKey key)
}
}

protected abstract IEnumerable<(TKey Key, TValue Value)> FindInternal(byte[] key_prefix);
/// <summary>
/// Find the entries that start with the `key_prefix`
/// </summary>
/// <param name="key_prefix">Must maintain the deserialized format of TKey</param>
/// <returns>Entries found with the desired prefix</returns>
public IEnumerable<(TKey Key, TValue Value)> Find(byte[] key_prefix = null)
{
var enumerator = Seek(key_prefix).GetEnumerator();
while (enumerator.MoveNext())
if (enumerator.Current.key.ToArray().AsSpan().StartsWith(key_prefix))
yield return enumerator.Current;
}

public IEnumerable<(TKey Key, TValue Value)> FindRange(TKey start, TKey end)
{
var enumerator = Seek(start.ToArray()).GetEnumerator();
var endKey = end?.ToArray();
while (enumerator.MoveNext())
if (endKey is null || ByteArrayComparer.Default.Compare(enumerator.Current.key.ToArray(), endKey) < 0)
yield return enumerator.Current;
}

protected abstract IEnumerable<(TKey Key, TValue Value)> SeekInternal(byte[] key_prefix);

public IEnumerable<Trackable> GetChangeSet()
{
Expand Down
2 changes: 1 addition & 1 deletion src/neo/Persistence/IReadOnlyStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Neo.Persistence
/// </summary>
public interface IReadOnlyStore
{
IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix);
IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] key);
byte[] TryGet(byte table, byte[] key);
}
}
7 changes: 3 additions & 4 deletions src/neo/Persistence/MemorySnapshot.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Neo.IO;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
Expand Down Expand Up @@ -41,11 +40,11 @@ public void Dispose()
{
}

public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix)
public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] key)
{
IEnumerable<KeyValuePair<byte[], byte[]>> records = immutableData[table];
if (prefix?.Length > 0)
records = records.Where(p => p.Key.AsSpan().StartsWith(prefix));
if (key?.Length > 0)
records = records.Where(p => ByteArrayComparer.Default.Compare(p.Key, key) >= 0);
records = records.OrderBy(p => p.Key, ByteArrayComparer.Default);
return records.Select(p => (p.Key, p.Value));
}
Expand Down
7 changes: 3 additions & 4 deletions src/neo/Persistence/MemoryStore.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Neo.IO;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -26,11 +25,11 @@ public void Dispose()
{
}

public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix)
public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] key)
{
IEnumerable<KeyValuePair<byte[], byte[]>> records = innerData[table];
if (prefix?.Length > 0)
records = records.Where(p => p.Key.AsSpan().StartsWith(prefix));
if (key?.Length > 0)
records = records.Where(p => ByteArrayComparer.Default.Compare(p.Key, key) >= 0);
records = records.OrderBy(p => p.Key, ByteArrayComparer.Default);
foreach (var pair in records)
yield return (pair.Key, pair.Value);
Expand Down
4 changes: 2 additions & 2 deletions src/neo/Persistence/StoreDataCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ protected override void DeleteInternal(TKey key)
snapshot?.Delete(prefix, key.ToArray());
}

protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix)
protected override IEnumerable<(TKey, TValue)> SeekInternal(byte[] key)
{
return store.Find(prefix, key_prefix).Select(p => (p.Key.AsSerializable<TKey>(), p.Value.AsSerializable<TValue>()));
return store.Seek(prefix, key).Select(p => (p.Key.AsSerializable<TKey>(), p.Value.AsSerializable<TValue>()));
}

protected override TValue GetInternal(TKey key)
Expand Down
10 changes: 10 additions & 0 deletions src/neo/SmartContract/Native/NativeContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,21 @@ protected StorageKey CreateStorageKey(byte prefix, byte[] key = null)
return storageKey;
}

protected StorageKey CreateStorageKey(byte prefix, uint key)
{
return CreateStorageKey(prefix, BitConverter.GetBytes(key));
}

internal protected StorageKey CreateStorageKey(byte prefix, ISerializable key)
{
return CreateStorageKey(prefix, key.ToArray());
}

internal protected StorageKey CreateStorageKey(byte prefix, ISerializable keyLeft, uint keyRight)
{
return CreateStorageKey(prefix, keyLeft.ToArray().Concat(BitConverter.GetBytes(keyRight)).ToArray());
}

public static NativeContract GetContract(UInt160 hash)
{
contractsHashDictionary.TryGetValue(hash, out var contract);
Expand Down
139 changes: 139 additions & 0 deletions src/neo/SmartContract/Native/Tokens/NeoToken.Economic.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using Neo.Cryptography.ECC;
using Neo.Ledger;
using Neo.Persistence;
using System;
using System.Numerics;

namespace Neo.SmartContract.Native.Tokens
{
public partial class NeoToken
{
private const byte Prefix_GasPerBlock = 17;
private const byte Prefix_NeoHoldersRewardRatio = 73;
private const byte Prefix_CommitteeRewardRatio = 19;
private const byte Prefix_VotersRewardRatio = 67;

private const byte Prefix_VoterRewardPerCommittee = 23;
private const byte Prefix_HolderRewardPerBlock = 57;

private const byte RewardIndexOffset = 1;

[ContractMethod(0_05000000, CallFlags.AllowModifyStates)]
private bool SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock)
{
if (gasPerBlock < 0) return false;
if (!CheckCommitteeWitness(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 SetNeoHoldersRewardRatio(ApplicationEngine engine, int neoHoldersRewardRatio)
{
if (neoHoldersRewardRatio < 0 || neoHoldersRewardRatio > byte.MaxValue) return false;
if (!CheckCommitteeWitness(engine)) return false;
StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_NeoHoldersRewardRatio));
item.Value = new byte[] { (byte)neoHoldersRewardRatio };
return true;
}

[ContractMethod(0_05000000, CallFlags.AllowModifyStates)]
private bool SetCommitteeRewardRatio(ApplicationEngine engine, int committeesRewardRatio)
{
if (committeesRewardRatio < 0 || committeesRewardRatio > byte.MaxValue) return false;
if (!CheckCommitteeWitness(engine)) return false;
StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_CommitteeRewardRatio));
item.Value = new byte[] { (byte)committeesRewardRatio };
return true;
}

[ContractMethod(0_05000000, CallFlags.AllowModifyStates)]
private bool SetVotersRewardRatio(ApplicationEngine engine, int votersRewardRatio)
{
if (votersRewardRatio < 0 || votersRewardRatio > byte.MaxValue) return false;
if (!CheckCommitteeWitness(engine)) return false;
StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersRewardRatio));
item.Value = new byte[] { (byte)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)]
public int GetNeoHoldersRewardRatio(StoreView snapshot)
{
return snapshot.Storages.TryGet(CreateStorageKey(Prefix_NeoHoldersRewardRatio)).Value[0];
}

[ContractMethod(1_00000000, CallFlags.AllowStates)]
public int GetCommitteeRewardRatio(StoreView snapshot)
{
return snapshot.Storages.TryGet(CreateStorageKey(Prefix_CommitteeRewardRatio)).Value[0];
}

[ContractMethod(1_00000000, CallFlags.AllowStates)]
public int GetVotersRewardRatio(StoreView snapshot)
{
return snapshot.Storages.TryGet(CreateStorageKey(Prefix_VotersRewardRatio)).Value[0];
}

private int GetTotalRewardRatio(StoreView snapshot)
{
return GetVotersRewardRatio(snapshot) + GetCommitteeRewardRatio(snapshot) + GetNeoHoldersRewardRatio(snapshot);
}

private void DistributeGas(ApplicationEngine engine, UInt160 account, NeoAccountState state)
{
BigInteger gas = CalculateBonus(engine.Snapshot, state.VoteTo, state.Balance, state.BalanceHeight, engine.Snapshot.PersistingBlock.Index);
state.BalanceHeight = engine.Snapshot.PersistingBlock.Index;
GAS.Mint(engine, account, gas);
}

private BigInteger CalculateBonus(StoreView snapshot, ECPoint votee, BigInteger value, uint start, uint end)
{
if (value.IsZero || start >= end) return BigInteger.Zero;
if (value.Sign < 0) throw new ArgumentOutOfRangeException(nameof(value));

BigInteger neoHolderReward = CalculateNeoHolderBonus(snapshot, value, start, end);
if (votee is null) return neoHolderReward;

var voteAddr = Contract.CreateSignatureContract(votee).ScriptHash;
var endKey = CreateStorageKey(Prefix_VoterRewardPerCommittee, voteAddr, uint.MaxValue - start - RewardIndexOffset);
var startKey = CreateStorageKey(Prefix_VoterRewardPerCommittee, voteAddr, uint.MaxValue - end - RewardIndexOffset);
var borderKey = CreateStorageKey(Prefix_VoterRewardPerCommittee, voteAddr, uint.MaxValue);

var enumerator = snapshot.Storages.FindRange(startKey, endKey).GetEnumerator();
if (!enumerator.MoveNext()) return neoHolderReward;

var endRewardPerNeo = new BigInteger(enumerator.Current.Value.Value);
var startRewardPerNeo = BigInteger.Zero;

enumerator = snapshot.Storages.FindRange(endKey, borderKey).GetEnumerator();
if (enumerator.MoveNext())
startRewardPerNeo = new BigInteger(enumerator.Current.Value.Value);

return neoHolderReward + value * (endRewardPerNeo - startRewardPerNeo);
}

private BigInteger CalculateNeoHolderBonus(StoreView snapshot, BigInteger value, uint start, uint end)
{
var endRewardItem = snapshot.Storages.TryGet(CreateStorageKey(Prefix_HolderRewardPerBlock, uint.MaxValue - end - RewardIndexOffset));
var startRewardItem = snapshot.Storages.TryGet(CreateStorageKey(Prefix_HolderRewardPerBlock, uint.MaxValue - start - RewardIndexOffset));
return value * (new BigInteger(endRewardItem.Value) - new BigInteger(startRewardItem.Value));
}

[ContractMethod(0_03000000, CallFlags.AllowStates)]
public BigInteger UnclaimedGas(StoreView snapshot, UInt160 account, uint end)
{
StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account));
if (storage is null) return BigInteger.Zero;
NeoAccountState state = storage.GetInteroperable<NeoAccountState>();
return CalculateBonus(snapshot, state.VoteTo, state.Balance, state.BalanceHeight, end);
}
}
}
Loading