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

Oracle policy contract #1445

Merged
merged 47 commits into from
Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
074fc9a
first commit
doubiliu Feb 13, 2020
d173f4c
Merge remote-tracking branch 'upstream/master' into OraclePolicyContract
doubiliu Feb 13, 2020
25b82cd
format
doubiliu Feb 13, 2020
04fdf94
Simplify code
doubiliu Feb 14, 2020
e4dc1ac
add UT and add some feature
doubiliu Feb 14, 2020
80bc65f
Fix bug
doubiliu Feb 15, 2020
aadf197
Add summary and fix bug
doubiliu Feb 15, 2020
748a3af
format
doubiliu Feb 16, 2020
3c40655
format
doubiliu Feb 17, 2020
6bf9c86
little change
doubiliu Feb 17, 2020
6e3369a
little change
doubiliu Feb 17, 2020
846d195
little change
doubiliu Feb 17, 2020
8b118c0
change Fee & Fix bug
doubiliu Feb 18, 2020
5d375c8
Optimize
shargon Feb 18, 2020
71e6add
add config class
doubiliu Feb 20, 2020
3570d0e
solve conflict
doubiliu Feb 20, 2020
bbdf3f9
FiX UT
doubiliu Feb 20, 2020
2197407
Format
doubiliu Feb 20, 2020
a81a1e5
Fix UT
doubiliu Feb 20, 2020
f4e69dc
Fix format and Optimize
doubiliu Feb 20, 2020
0c2b34b
Add some UT
shargon Feb 20, 2020
591b33b
Fix bug and add UT
doubiliu Feb 21, 2020
61bb96a
Update src/neo/SmartContract/Native/Oracle/OraclePolicyContract.cs
doubiliu Feb 21, 2020
531427e
little change
doubiliu Feb 21, 2020
2d8a645
format
doubiliu Feb 21, 2020
99d6761
Update src/neo/SmartContract/Native/Oracle/OraclePolicyContract.cs
doubiliu Feb 21, 2020
cc6774f
add check
doubiliu Feb 21, 2020
8698a5b
Merge branch 'OraclePolicyContract' of github.com:doubiliu/neoUT into…
doubiliu Feb 21, 2020
696399c
change validator
doubiliu Feb 23, 2020
9dfc1f8
Add double initialization check
shargon Feb 24, 2020
5d9fa90
add UT
doubiliu Feb 26, 2020
740ccb7
Add UT
doubiliu Feb 26, 2020
c693e7c
change UT
doubiliu Feb 26, 2020
30577c5
fill UT
Feb 27, 2020
985f0a4
up ut and fix NeoToken.GetValidators
Feb 27, 2020
d042560
remove console
Feb 27, 2020
704051a
reset NEO.getValidators
Feb 28, 2020
953a288
fix GetOracleValidators
Mar 2, 2020
aad74d9
Rename variable
shargon Mar 2, 2020
0c0f9e3
Update src/neo/SmartContract/Native/Oracle/OracleContract.cs
doubiliu Mar 3, 2020
8876540
Update src/neo/SmartContract/Native/Oracle/OracleContract.cs
doubiliu Mar 3, 2020
2a41962
Fix bug
doubiliu Mar 3, 2020
e6bb7b9
change logic
doubiliu Mar 4, 2020
66aea1f
Fix name
doubiliu Mar 4, 2020
19447cd
change to const
doubiliu Mar 5, 2020
7e64f2c
Add double initialization check and fix ut
Mar 11, 2020
65b823b
optimize
Mar 11, 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
2 changes: 2 additions & 0 deletions src/neo/SmartContract/Native/NativeContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using Neo.IO;
using Neo.Ledger;
using Neo.Oracle;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Native.Tokens;
using Neo.VM;
Expand All @@ -23,6 +24,7 @@ public abstract class NativeContract
public static NeoToken NEO { get; } = new NeoToken();
public static GasToken GAS { get; } = new GasToken();
public static PolicyContract Policy { get; } = new PolicyContract();
public static OracleContract Oracle { get; } = new OracleContract();

public abstract string ServiceName { get; }
public uint ServiceHash { get; }
Expand Down
229 changes: 229 additions & 0 deletions src/neo/SmartContract/Native/Oracle/OracleContract.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.Ledger;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Native;
using Neo.SmartContract.Native.Oracle;
using Neo.VM;
using Neo.VM.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Array = Neo.VM.Types.Array;

namespace Neo.Oracle
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
{
public sealed class OracleContract : NativeContract
{
public override string ServiceName => "Neo.Native.Oracle.Policy";
doubiliu marked this conversation as resolved.
Show resolved Hide resolved

public override int Id => -4;

private const byte Prefix_Validator = 24;
private const byte Prefix_HttpConfig = 25;
private const byte Prefix_PerRequestFee = 26;

public OracleContract()
{
Manifest.Features = ContractFeatures.HasStorage;
}

internal override bool Initialize(ApplicationEngine engine)
{
if (!base.Initialize(engine)) return false;
shargon marked this conversation as resolved.
Show resolved Hide resolved
engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_HttpConfig), new StorageItem
{
Value = new OracleHttpConfig() { Timeout = 5000 }.ToArray()
});
engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_PerRequestFee), new StorageItem
{
Value = BitConverter.GetBytes(1000)
});
return true;
}

/// <summary>
/// Consensus node can delegate third party to operate Oracle nodes
/// </summary>
/// <param name="engine">VM</param>
/// <param name="args">Parameter Array</param>
/// <returns>Returns true if the execution is successful, otherwise returns false</returns>
[ContractMethod(0_03000000, ContractParameterType.Boolean, ParameterTypes = new[] { ContractParameterType.ByteArray, ContractParameterType.ByteArray }, ParameterNames = new[] { "consignorPubKey", "consigneePubKey" })]
private StackItem DelegateOracleValidator(ApplicationEngine engine, Array args)
{
StoreView snapshot = engine.Snapshot;
ECPoint consignorPubKey = args[0].GetSpan().AsSerializable<ECPoint>();
ECPoint consigneePubKey = args[1].GetSpan().AsSerializable<ECPoint>();
ECPoint[] oraclePubKeys = NativeContract.NEO.GetValidators(snapshot);
if (!oraclePubKeys.Contains(consignorPubKey)) return false;
UInt160 account = Contract.CreateSignatureRedeemScript(consignorPubKey).ToScriptHash();
if (!InteropService.Runtime.CheckWitnessInternal(engine, account)) return false;
StorageKey key = CreateStorageKey(Prefix_Validator, consignorPubKey);
StorageItem item = snapshot.Storages.GetAndChange(key, () => new StorageItem());
item.Value = consigneePubKey.ToArray();

byte[] prefixKey = StorageKey.CreateSearchPrefix(Id, new[] { Prefix_Validator });
List<ECPoint> delegatedOracleValidators = snapshot.Storages.Find(prefixKey).Select(p =>
(
p.Key.Key.AsSerializable<ECPoint>(1)
)).ToList();
foreach (var validator in delegatedOracleValidators)
{
if (!oraclePubKeys.Contains(validator))
{
Console.WriteLine("start to delete invalidator....");
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
snapshot.Storages.Delete(CreateStorageKey(Prefix_Validator, validator));
}
}
return true;
}

/// <summary>
/// Get current authorized Oracle validator.
/// </summary>
/// <param name="engine">VM</param>
/// <param name="args">Parameter Array</param>
/// <returns>Authorized Oracle validator</returns>
[ContractMethod(0_01000000, ContractParameterType.Array)]
private StackItem GetOracleValidators(ApplicationEngine engine, Array args)
{
return new Array(engine.ReferenceCounter, GetOracleValidators(engine.Snapshot).Select(p => (StackItem)p.ToArray()));
}

/// <summary>
/// Get current authorized Oracle validator
/// </summary>
/// <param name="snapshot">snapshot</param>
/// <returns>Authorized Oracle validator</returns>
public ECPoint[] GetOracleValidators(StoreView snapshot)
{
ECPoint[] oraclePubKeys = NativeContract.NEO.GetValidators(snapshot);
for (int index = 0; index < oraclePubKeys.Length; index++)
{
var oraclePubKey = oraclePubKeys[index];
StorageKey key = CreateStorageKey(Prefix_Validator, oraclePubKey);
ECPoint delegatePubKey = snapshot.Storages.TryGet(key)?.Value.AsSerializable<ECPoint>();
if (delegatePubKey != null) { oraclePubKeys[index] = delegatePubKey; }
}
return oraclePubKeys;
shargon marked this conversation as resolved.
Show resolved Hide resolved
}

/// <summary>
/// Get number of current authorized Oracle validator
/// </summary>
/// <param name="engine">VM</param>
/// <param name="args">Parameter Array</param>
/// <returns>The number of authorized Oracle validator</returns>
[ContractMethod(0_01000000, ContractParameterType.Integer)]
private StackItem GetOracleValidatorsCount(ApplicationEngine engine, Array args)
{
return GetOracleValidatorsCount(engine.Snapshot);
}

/// <summary>
/// Get number of current authorized Oracle validator
/// </summary>
/// <param name="snapshot">snapshot</param>
/// <returns>The number of authorized Oracle validator</returns>
public BigInteger GetOracleValidatorsCount(StoreView snapshot)
{
return GetOracleValidators(snapshot).Length;
}

/// <summary>
/// Create a Oracle multisignature address
/// </summary>
/// <param name="snapshot">snapshot</param>
/// <returns>Oracle multisignature address</returns>
public UInt160 GetOracleMultiSigAddress(StoreView snapshot)
{
ECPoint[] validators = NativeContract.NEO.GetValidators(snapshot);
return Contract.CreateMultiSigRedeemScript(validators.Length - (validators.Length - 1) / 3, validators).ToScriptHash();
}

/// <summary>
/// Set HttpConfig
/// </summary>
/// <param name="engine">VM</param>
/// <param name="args">Parameter Array</param>
/// <returns>Returns true if the execution is successful, otherwise returns false</returns>
[ContractMethod(0_03000000, ContractParameterType.Boolean, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "httpConfig" })]
private StackItem SetHttpConfig(ApplicationEngine engine, Array args)
Copy link
Member

Choose a reason for hiding this comment

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

If we have multiple settings in HttpConfig, do we have to set all of them at once?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but if you have other ideas, I can change

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can get or set it by key. For example:

GetConfig("HttpTimeout");
SetConfig("HttpTimeout", 2000);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@shargon What's your opinion?

Copy link
Contributor

Choose a reason for hiding this comment

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

Use this way?

SetHttpConfig("Timeout", 2000) // put: http+timeout => 2000
GetHttpConfig()  // return all the http configurations

Copy link
Member

Choose a reason for hiding this comment

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

If we use enum or const for the name, it's good for me :)

{
StoreView snapshot = engine.Snapshot;
UInt160 account = GetOracleMultiSigAddress(snapshot);
if (!InteropService.Runtime.CheckWitnessInternal(engine, account)) return false;
int timeOutMilliSeconds = (int)args[0].GetBigInteger();
if (timeOutMilliSeconds <= 0) return false;
OracleHttpConfig httpConfig = new OracleHttpConfig() { Timeout = timeOutMilliSeconds };
StorageItem storage = snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_HttpConfig));
storage.Value = httpConfig.ToArray();
return true;
}

/// <summary>
/// Get HttpConfig
/// </summary>
/// <param name="engine">VM</param>
/// <returns>value</returns>
[ContractMethod(0_01000000, ContractParameterType.Array)]
private StackItem GetHttpConfig(ApplicationEngine engine, Array args)
{
return GetHttpConfig(engine.Snapshot).ToStackItem(engine.ReferenceCounter);
}

/// <summary>
/// Get HttpConfig
/// </summary>
/// <param name="snapshot">snapshot</param>
/// <returns>value</returns>
public OracleHttpConfig GetHttpConfig(StoreView snapshot)
{
return snapshot.Storages[CreateStorageKey(Prefix_HttpConfig)].Value.AsSerializable<OracleHttpConfig>();
}

/// <summary>
/// Set PerRequestFee
/// </summary>
/// <param name="engine">VM</param>
/// <param name="args">Parameter Array</param>
/// <returns>Returns true if the execution is successful, otherwise returns false</returns>
[ContractMethod(0_03000000, ContractParameterType.Boolean, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "fee" })]
private StackItem SetPerRequestFee(ApplicationEngine engine, Array args)
{
StoreView snapshot = engine.Snapshot;
UInt160 account = GetOracleMultiSigAddress(snapshot);
if (!InteropService.Runtime.CheckWitnessInternal(engine, account)) return false;
int perRequestFee = (int)args[0].GetBigInteger();
if (perRequestFee <= 0) return false;
StorageItem storage = snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_PerRequestFee));
storage.Value = BitConverter.GetBytes(perRequestFee);
return true;
}

/// <summary>
/// Get PerRequestFee
/// </summary>
/// <param name="engine">VM</param>
/// <param name="args">Parameter Array</param>
/// <returns>Value</returns>
[ContractMethod(0_01000000, ContractParameterType.Integer, SafeMethod = true)]
private StackItem GetPerRequestFee(ApplicationEngine engine, Array args)
{
return new Integer(GetPerRequestFee(engine.Snapshot));
}

/// <summary>
/// Get PerRequestFee
/// </summary>
/// <param name="snapshot">snapshot</param>
/// <returns>Value</returns>
public int GetPerRequestFee(StoreView snapshot)
{
return BitConverter.ToInt32(snapshot.Storages[CreateStorageKey(Prefix_PerRequestFee)].Value, 0);
}
}
}
32 changes: 32 additions & 0 deletions src/neo/SmartContract/Native/Oracle/OracleHttpConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Neo.IO;
using Neo.VM;
using Neo.VM.Types;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Neo.SmartContract.Native.Oracle
{
public class OracleHttpConfig : ISerializable, IInteroperable
{
public int Timeout { get; set; }

public int Size => sizeof(int);

public void Deserialize(BinaryReader reader)
{
Timeout = reader.ReadInt32();
}

public void Serialize(BinaryWriter writer)
{
writer.Write(Timeout);
}

public StackItem ToStackItem(ReferenceCounter referenceCounter)
{
return new VM.Types.Array(referenceCounter, new StackItem[] { Timeout });
}
}
}
8 changes: 7 additions & 1 deletion src/neo/SmartContract/Native/Tokens/NeoToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ private StackItem GetRegisteredValidators(ApplicationEngine engine, Array args)
public IEnumerable<(ECPoint PublicKey, BigInteger Votes)> GetRegisteredValidators(StoreView snapshot)
{
byte[] prefix_key = StorageKey.CreateSearchPrefix(Id, new[] { Prefix_Validator });
Console.WriteLine("get register validator key: " + prefix_key.ToHexString());
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
return snapshot.Storages.Find(prefix_key).Select(p =>
(
p.Key.Key.AsSerializable<ECPoint>(1),
Expand All @@ -219,7 +220,12 @@ private StackItem GetValidators(ApplicationEngine engine, Array args)
public ECPoint[] GetValidators(StoreView snapshot)
{
StorageItem storage_count = snapshot.Storages.TryGet(CreateStorageKey(Prefix_ValidatorsCount));
if (storage_count is null) return Blockchain.StandbyValidators;
if (storage_count is null)
{
ECPoint[] validators = new ECPoint[Blockchain.StandbyValidators.Length];
System.Array.Copy(Blockchain.StandbyValidators, validators, validators.Length);
Copy link
Contributor

@Tommo-L Tommo-L Feb 27, 2020

Choose a reason for hiding this comment

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

It's not safe here, I've added a temporary array to prevent the data from being tampered outside.

Copy link
Member

Choose a reason for hiding this comment

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

Could you create another PR in master, because oracle will spend more time in be merged

Copy link
Contributor

@Tommo-L Tommo-L Feb 28, 2020

Choose a reason for hiding this comment

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

Okay, PR #1458. I'll reset it. But ut will fail.

return validators;
}
ValidatorsCountState state_count = ValidatorsCountState.FromByteArray(storage_count.Value);
int count = (int)state_count.Votes.Select((p, i) => new
{
Expand Down
4 changes: 2 additions & 2 deletions src/neo/neo.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

doubiliu marked this conversation as resolved.
Show resolved Hide resolved
<PropertyGroup>
<Copyright>2015-2019 The Neo Project</Copyright>
Expand Down Expand Up @@ -30,4 +30,4 @@
<PackageReference Include="Neo.VM" Version="3.0.0-CI00201" />
</ItemGroup>

</Project>
</Project>
Loading