Skip to content

Commit

Permalink
Add Designate contract (neo-project#1950)
Browse files Browse the repository at this point in the history
* add designate contract

* format

* fix

* Some checks

* reorganize file

* Remove empty line

* Update DesignateContract.cs

* ArgumentOutOfRangeException

* Update DesignateContract.cs

* Remove OracleContract.Lists.cs

Co-authored-by: Shargon <shargon@gmail.com>
Co-authored-by: erikzhang <erik@neo.org>
  • Loading branch information
3 people authored and Shawn committed Jan 8, 2021
1 parent 0a57860 commit 8424efa
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 63 deletions.
3 changes: 2 additions & 1 deletion src/neo/Network/P2P/Payloads/OracleResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Neo.Persistence;
using Neo.SmartContract.Native;
using Neo.SmartContract.Native.Oracle;
using Neo.SmartContract.Native.Designate;
using Neo.VM;
using System;
using System.IO;
Expand Down Expand Up @@ -70,7 +71,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/Designate/DesignateContract.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma warning disable IDE0051

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.Designate
{
public sealed class DesignateContract : NativeContract
{
public override string Name => "Designation";
public override int Id => -5;

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

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

[ContractMethod(0_01000000, CallFlags.AllowStates)]
public ECPoint[] GetDesignatedByRole(StoreView snapshot, Role role)
{
if (!Enum.IsDefined(typeof(Role), role))
throw new ArgumentOutOfRangeException(nameof(role));
return snapshot.Storages[CreateStorageKey((byte)role)].GetInteroperable<NodeList>().ToArray();
}

[ContractMethod(0, CallFlags.AllowModifyStates)]
private void DesignateAsRole(ApplicationEngine engine, Role role, ECPoint[] nodes)
{
if (nodes.Length == 0) throw new ArgumentException(nameof(nodes));
if (!Enum.IsDefined(typeof(Role), role))
throw new ArgumentOutOfRangeException(nameof(role));
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 (VM.Types.Array)stackItem)
Add(ECPoint.DecodePoint(item.GetSpan(), ECCurve.Secp256r1));
}

public StackItem ToStackItem(ReferenceCounter referenceCounter)
{
return new VM.Types.Array(referenceCounter, this.Select(p => (StackItem)p.ToArray()));
}
}
}
}
8 changes: 8 additions & 0 deletions src/neo/SmartContract/Native/Designate/Role.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Neo.SmartContract.Native.Designate
{
public enum Role : byte
{
StateValidator = 4,
Oracle = 8
}
}
2 changes: 2 additions & 0 deletions src/neo/SmartContract/Native/NativeContract.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Neo.IO;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Native.Designate;
using Neo.SmartContract.Native.Oracle;
using Neo.SmartContract.Native.Tokens;
using Neo.VM;
Expand All @@ -25,6 +26,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
40 changes: 0 additions & 40 deletions src/neo/SmartContract/Native/Oracle/OracleContract.Lists.cs

This file was deleted.

40 changes: 18 additions & 22 deletions src/neo/SmartContract/Native/Oracle/OracleContract.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#pragma warning disable IDE0051

using Neo.Cryptography;
using Neo.Cryptography.ECC;
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Native.Designate;
using Neo.VM;
using Neo.VM.Types;
using System;
using System.Collections.Generic;
Expand All @@ -14,14 +15,13 @@

namespace Neo.SmartContract.Native.Oracle
{
public sealed partial class OracleContract : NativeContract
public sealed class OracleContract : NativeContract
{
private const int MaxUrlLength = 256;
private const int MaxFilterLength = 128;
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 +48,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 +82,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 +107,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, 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,22 +160,25 @@ 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)
{
Transaction tx = (Transaction)engine.ScriptContainer;
return tx?.GetAttribute<OracleResponse>() != null;
}

private class IdList : List<ulong>, IInteroperable
{
public void FromStackItem(StackItem stackItem)
{
foreach (StackItem item in (VM.Types.Array)stackItem)
Add((ulong)item.GetInteger());
}

public StackItem ToStackItem(ReferenceCounter referenceCounter)
{
return new VM.Types.Array(referenceCounter, this.Select(p => (Integer)p));
}
}
}
}

0 comments on commit 8424efa

Please sign in to comment.