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 Designate contract #1950

Merged
merged 12 commits into from
Sep 23, 2020
2 changes: 1 addition & 1 deletion src/neo/Network/P2P/Payloads/OracleResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public override bool Verify(StoreView snapshot, Transaction tx)
OracleRequest request = NativeContract.Oracle.GetRequest(snapshot, Id);
if (request is null) return false;
if (tx.NetworkFee + tx.SystemFee != request.GasForResponse) return false;
UInt160 oracleAccount = Blockchain.GetConsensusAddress(NativeContract.Oracle.GetOracleNodes(snapshot));
UInt160 oracleAccount = Blockchain.GetConsensusAddress(NativeContract.Designate.GetDesignatedByRole(snapshot, Role.Oracle));
return tx.Signers.Any(p => p.Account.Equals(oracleAccount));
}
}
Expand Down
70 changes: 70 additions & 0 deletions src/neo/SmartContract/Native/DesignateContract.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Neo.Cryptography;
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.Ledger;
using Neo.Persistence;
using Neo.SmartContract.Manifest;
using Neo.VM;
using Neo.VM.Types;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Neo.SmartContract.Native
{
public enum Role : byte
{
StateValidator = 4,
Oracle = 8
}

public sealed class DesignateContract : NativeContract
shargon marked this conversation as resolved.
Show resolved Hide resolved
{
public override string Name => "Designation";
public override int Id => -5;

internal DesignateContract()
{
Manifest.Features = ContractFeatures.HasStorage;
}

internal override void Initialize(ApplicationEngine engine)
{
foreach (var role in Enum.GetValues(typeof(Role)))
{
engine.Snapshot.Storages.Add(CreateStorageKey((byte)role), new StorageItem(new NodeList()));
}
}

[ContractMethod(0_01000000, CallFlags.AllowStates)]
public ECPoint[] GetDesignatedByRole(StoreView snapshot, Role role)
{
return snapshot.Storages[CreateStorageKey((byte)role)].GetInteroperable<NodeList>().ToArray();
}

[ContractMethod(0, CallFlags.AllowModifyStates)]
private void DesignateAsRole(ApplicationEngine engine, ECPoint[] nodes, Role role)
{
if (nodes.Length == 0) throw new ArgumentException();
if (!CheckCommittee(engine)) throw new InvalidOperationException();
NodeList list = engine.Snapshot.Storages.GetAndChange(CreateStorageKey((byte)role)).GetInteroperable<NodeList>();
list.Clear();
list.AddRange(nodes);
list.Sort();
}

private class NodeList : List<ECPoint>, IInteroperable
{
public void FromStackItem(StackItem stackItem)
{
foreach (StackItem item in (Neo.VM.Types.Array)stackItem)
Add(ECPoint.DecodePoint(item.GetSpan(), ECCurve.Secp256r1));
}

public StackItem ToStackItem(ReferenceCounter referenceCounter)
{
return new Neo.VM.Types.Array(referenceCounter, this.Select(p => (StackItem)p.ToArray()));
}
}
}
}
1 change: 1 addition & 0 deletions src/neo/SmartContract/Native/NativeContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public abstract class NativeContract
public static GasToken GAS { get; } = new GasToken();
public static PolicyContract Policy { get; } = new PolicyContract();
public static OracleContract Oracle { get; } = new OracleContract();
public static DesignateContract Designate { get; } = new DesignateContract();

[ContractMethod(0, CallFlags.None)]
public abstract string Name { get; }
Expand Down
16 changes: 0 additions & 16 deletions src/neo/SmartContract/Native/Oracle/OracleContract.Lists.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.VM;
using Neo.VM.Types;
using System.Collections.Generic;
Expand All @@ -22,19 +20,5 @@ public StackItem ToStackItem(ReferenceCounter referenceCounter)
return new Array(referenceCounter, this.Select(p => (Integer)p));
}
}

private class NodeList : List<ECPoint>, IInteroperable
{
public void FromStackItem(StackItem stackItem)
{
foreach (StackItem item in (Array)stackItem)
Add(ECPoint.DecodePoint(item.GetSpan(), ECCurve.Secp256r1));
}

public StackItem ToStackItem(ReferenceCounter referenceCounter)
{
return new Array(referenceCounter, this.Select(p => (StackItem)p.ToArray()));
}
}
}
}
22 changes: 1 addition & 21 deletions src/neo/SmartContract/Native/Oracle/OracleContract.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma warning disable IDE0051

using Neo.Cryptography;
using Neo.Cryptography.ECC;
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
Expand All @@ -21,7 +20,6 @@ public sealed partial class OracleContract : NativeContract
private const int MaxCallbackLength = 32;
private const int MaxUserDataLength = 512;

private const byte Prefix_NodeList = 8;
private const byte Prefix_RequestId = 9;
private const byte Prefix_Request = 7;
private const byte Prefix_IdList = 6;
Expand All @@ -48,12 +46,6 @@ private void Finish(ApplicationEngine engine)
engine.CallFromNativeContract(null, request.CallbackContract, request.CallbackMethod, request.Url, userData, (int)response.Code, response.Result);
}

[ContractMethod(0_01000000, CallFlags.AllowStates)]
public ECPoint[] GetOracleNodes(StoreView snapshot)
{
return snapshot.Storages[CreateStorageKey(Prefix_NodeList)].GetInteroperable<NodeList>().ToArray();
}

private UInt256 GetOriginalTxid(ApplicationEngine engine)
{
Transaction tx = (Transaction)engine.ScriptContainer;
Expand Down Expand Up @@ -88,7 +80,6 @@ private static byte[] GetUrlHash(string url)

internal override void Initialize(ApplicationEngine engine)
{
engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_NodeList), new StorageItem(new NodeList()));
engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BitConverter.GetBytes(0ul)));
}

Expand All @@ -114,7 +105,7 @@ protected override void PostPersist(ApplicationEngine engine)
if (list.Count == 0) engine.Snapshot.Storages.Delete(key);

//Mint GAS for oracle nodes
nodes ??= GetOracleNodes(engine.Snapshot).Select(p => (Contract.CreateSignatureRedeemScript(p).ToScriptHash(), BigInteger.Zero)).ToArray();
nodes ??= NativeContract.Designate.GetDesignatedByRole(engine.Snapshot, Native.Role.Oracle).Select(p => (Contract.CreateSignatureRedeemScript(p).ToScriptHash(), BigInteger.Zero)).ToArray();
if (nodes.Length > 0)
{
int index = (int)(response.Id % (ulong)nodes.Length);
Expand Down Expand Up @@ -167,17 +158,6 @@ private void Request(ApplicationEngine engine, string url, string filter, string
engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_IdList).Add(GetUrlHash(url)), () => new StorageItem(new IdList())).GetInteroperable<IdList>().Add(id);
}

[ContractMethod(0, CallFlags.AllowModifyStates)]
private void SetOracleNodes(ApplicationEngine engine, ECPoint[] nodes)
{
if (nodes.Length == 0) throw new ArgumentException();
if (!CheckCommittee(engine)) throw new InvalidOperationException();
NodeList list = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_NodeList)).GetInteroperable<NodeList>();
list.Clear();
list.AddRange(nodes);
list.Sort();
}

[ContractMethod(0_01000000, CallFlags.None)]
private bool Verify(ApplicationEngine engine)
{
Expand Down