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 3 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
186 changes: 186 additions & 0 deletions src/neo/Oracle/OraclePolicyContract.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Native;
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
{
public sealed class OraclePolicyContract : NativeContract
{
public override string ServiceName => "Neo.Native.Oracle.Policy";

public override int Id => -4;

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

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

[ContractMethod(0_01000000, ContractParameterType.Boolean, ParameterTypes = new[] { ContractParameterType.Hash160, ContractParameterType.Array }, ParameterNames = new[] { "account", "pubkeys" })]
private StackItem DelegateOracleValidator(ApplicationEngine engine, Array args)
{
UInt160 account = new UInt160(args[0].GetSpan());
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
if (!InteropService.Runtime.CheckWitnessInternal(engine, account)) return false;
ECPoint[] pubkeys = ((Array)args[1]).Select(p => p.GetSpan().AsSerializable<ECPoint>()).ToArray();
if (pubkeys.Length != 2) return false;
StoreView snapshot = engine.Snapshot;
StorageKey key = CreateStorageKey(Prefix_Validator, pubkeys[0]);
if (snapshot.Storages.TryGet(key) != null)
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
{
StorageItem value = snapshot.Storages.GetAndChange(key);
value.Value = pubkeys[1].ToArray();
}
else
{
snapshot.Storages.Add(key, new StorageItem
{
Value = pubkeys[1].ToArray()
});
}
return true;
}

public ECPoint[] GetOracleValidators(StoreView snapshot)
{
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
ECPoint[] consensusPublicKey = PolicyContract.NEO.GetValidators(snapshot);
IEnumerable<(ECPoint ConsensusPublicKey, ECPoint OraclePublicKey)> hasDelegateOracleValidators = GetDelegateOracleValidators(snapshot).Where(p => consensusPublicKey.Contains(p.ConsensusPublicKey));
hasDelegateOracleValidators.ToList().ForEach(p =>
{
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
var index = System.Array.IndexOf(consensusPublicKey, p.ConsensusPublicKey);
if (index >= 0) consensusPublicKey[index] = p.OraclePublicKey;
});
return consensusPublicKey;
}

public BigInteger GetOracleValidatorsCount(StoreView snapshot)
{
return GetOracleValidators(snapshot).Length;
}

internal IEnumerable<(ECPoint ConsensusPublicKey, ECPoint OraclePublicKey)> GetDelegateOracleValidators(StoreView snapshot)
{
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
byte[] prefix_key = StorageKey.CreateSearchPrefix(Id, new[] { Prefix_Validator });
return snapshot.Storages.Find(prefix_key).Select(p =>
(
p.Key.Key.AsSerializable<ECPoint>(1),
p.Value.Value.AsSerializable<ECPoint>(1)
));
}

[ContractMethod(0_03000000, ContractParameterType.Boolean, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "fee" })]
private StackItem SetTimeOutMilliSeconds(ApplicationEngine engine, Array args)
{
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
StoreView snapshot = engine.Snapshot;
Transaction tx = (Transaction)engine.ScriptContainer;
Array signatures = new Array(tx.Witnesses.ToList().Select(p => StackItem.FromInterface(p.VerificationScript)));
Array pubkeys = new Array(GetOracleValidators(snapshot).ToList().Select(p => StackItem.FromInterface(p)));
engine.CurrentContext.EvaluationStack.Push(signatures);
engine.CurrentContext.EvaluationStack.Push(pubkeys);
engine.CurrentContext.EvaluationStack.Push(StackItem.Null);

if (BitConverter.ToInt32(args[0].GetSpan()) <= 0) return false;
int timeOutMilliSeconds = BitConverter.ToInt32(args[0].GetSpan());
if (!InteropService.Crypto.ECDsaCheckMultiSig.Handler.Invoke(engine))
{
return false;
}
StorageKey key = CreateStorageKey(Prefix_TimeOutMilliSeconds);
if (snapshot.Storages.TryGet(key) != null)
{
StorageItem value = snapshot.Storages.GetAndChange(key);
value.Value = BitConverter.GetBytes(timeOutMilliSeconds);
return true;
}
else
{
snapshot.Storages.Add(key, new StorageItem
{
Value = BitConverter.GetBytes(timeOutMilliSeconds)
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
});
return true;
}
}

public int GetTimeOutMilliSeconds(StoreView snapshot)
{
StorageKey key = CreateStorageKey(Prefix_TimeOutMilliSeconds);
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
if (snapshot.Storages.TryGet(key) != null)
{
return BitConverter.ToInt32(snapshot.Storages.TryGet(key).Value, 0);
}
else
{
snapshot.Storages.Add(key, new StorageItem
{
Value = BitConverter.GetBytes(1000)
});
return 1000;
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
}
}

[ContractMethod(0_03000000, ContractParameterType.Boolean, ParameterTypes = new[] { ContractParameterType.Integer }, ParameterNames = new[] { "fee" })]
private StackItem SetPerRequestFee(ApplicationEngine engine, Array args)
{
StoreView snapshot = engine.Snapshot;
Transaction tx = (Transaction)engine.ScriptContainer;
Array signatures = new Array(tx.Witnesses.ToList().Select(p => StackItem.FromInterface(p.VerificationScript)));
Array pubkeys = new Array(GetOracleValidators(snapshot).ToList().Select(p => StackItem.FromInterface(p)));
engine.CurrentContext.EvaluationStack.Push(signatures);
engine.CurrentContext.EvaluationStack.Push(pubkeys);
engine.CurrentContext.EvaluationStack.Push(StackItem.Null);
if (BitConverter.ToInt32(args[0].GetSpan()) <= 0) return false;
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
int perRequestFee = BitConverter.ToInt32(args[0].GetSpan());
if (!InteropService.Crypto.ECDsaCheckMultiSig.Handler.Invoke(engine))
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
{
return false;
}
StorageKey key = CreateStorageKey(Prefix_PerRequestFee);
if (snapshot.Storages.TryGet(key) != null)
{
StorageItem value = snapshot.Storages.GetAndChange(key);
value.Value = BitConverter.GetBytes(perRequestFee);
return true;
}
else
{
snapshot.Storages.Add(key, new StorageItem
{
Value = BitConverter.GetBytes(perRequestFee)
});
return true;
}
}

public int GetPerRequestFee(SnapshotView snapshot)
{
StorageKey key = CreateStorageKey(Prefix_PerRequestFee);
doubiliu marked this conversation as resolved.
Show resolved Hide resolved
if (snapshot.Storages.TryGet(key) != null)
{
return BitConverter.ToInt32(snapshot.Storages.TryGet(key).Value, 0);
}
else
{
snapshot.Storages.Add(key, new StorageItem
{
Value = BitConverter.GetBytes(1000)
});
return 1000;
}
}
}
}
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 OraclePolicyContract OraclePolicy { get; } = new OraclePolicyContract();

public abstract string ServiceName { get; }
public uint ServiceHash { get; }
Expand Down
4 changes: 4 additions & 0 deletions src/neo/neo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@
<PackageReference Include="Neo.VM" Version="3.0.0-CI00201" />
</ItemGroup>

<ItemGroup>
<Folder Include="Oracle\" />
</ItemGroup>
doubiliu marked this conversation as resolved.
Show resolved Hide resolved

</Project>
116 changes: 116 additions & 0 deletions tests/neo.UnitTests/Oracle/UT_OraclePolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.Oracle;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.UnitTests.Extensions;
using Neo.VM;
using Neo.VM.Types;
using Neo.Wallets;
using System.Linq;
using System.Numerics;

namespace Neo.UnitTests.Oracle
{
[TestClass]
public class UT_OraclePolicy
{
[TestInitialize]
public void TestSetup()
{
TestBlockchain.InitializeMockNeoSystem();
}

[TestMethod]
public void Check_GetPerRequestFee()
{
var snapshot = Blockchain.Singleton.GetSnapshot();
// Fake blockchain
OraclePolicyContract contract = NativeContract.OraclePolicy;
Assert.AreEqual(contract.GetPerRequestFee(snapshot), 1000);
}

[TestMethod]
public void Check_GetTimeOutMilliSeconds()
{
var snapshot = Blockchain.Singleton.GetSnapshot();
// Fake blockchain
OraclePolicyContract contract = NativeContract.OraclePolicy;
Assert.AreEqual(contract.GetPerRequestFee(snapshot), 1000);
}

[TestMethod]
public void Check_GetOracleValidators()
{
var snapshot = Blockchain.Singleton.GetSnapshot();
// Fake blockchain
OraclePolicyContract contract = NativeContract.OraclePolicy;
ECPoint[] obj = contract.GetOracleValidators(snapshot);
Assert.AreEqual(obj.Length, 7);
}

[TestMethod]
public void Test_DelegateOracleValidator()
{
var snapshot = Blockchain.Singleton.GetSnapshot();
// Fake blockchain
OraclePolicyContract contract = NativeContract.OraclePolicy;
ECPoint[] obj = contract.GetOracleValidators(snapshot);
Assert.AreEqual(obj.Length, 7);

// Without signature
byte[] privateKey1 = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
KeyPair keyPair1 = new KeyPair(privateKey1);
ECPoint pubkey1 = keyPair1.PublicKey;

byte[] privateKey2 = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
KeyPair keyPair2 = new KeyPair(privateKey2);
ECPoint pubkey2 = keyPair2.PublicKey;

Array array = new Array();
array.Add(StackItem.FromInterface(privateKey1));
array.Add(StackItem.FromInterface(privateKey2));

/* var ret = NativeContract.OraclePolicy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(),
"DelegateOracleValidator", new ContractParameter(ContractParameterType.Hash160) { Value = 1 }, new ContractParameter(ContractParameterType.Array) { Value = array });
ret.Should().BeOfType<VM.Types.Boolean>();
ret.ToBoolean().Should().BeFalse();*/
}
internal static (bool State, bool Result) Check_DelegateOracleValidator(StoreView snapshot, byte[] account, byte[][] pubkeys, bool signAccount)
{
var engine = new ApplicationEngine(TriggerType.Application,
new Nep5NativeContractExtensions.ManualWitness(signAccount ? new UInt160(account) : UInt160.Zero), snapshot, 0, true);

engine.LoadScript(NativeContract.OraclePolicy.Script);

var script = new ScriptBuilder();

foreach (var ec in pubkeys) script.EmitPush(ec);
script.EmitPush(pubkeys.Length);
script.Emit(OpCode.PACK);

script.EmitPush(account.ToArray());
script.EmitPush(2);
script.Emit(OpCode.PACK);
script.EmitPush("DelegateOracleValidator");
engine.LoadScript(script.ToArray());

if (engine.Execute() == VMState.FAULT)
{
return (false, false);
}

var result = engine.ResultStack.Pop();
result.Should().BeOfType(typeof(VM.Types.Boolean));

return (true, result.ToBoolean());
}
}
}
4 changes: 4 additions & 0 deletions tests/neo.UnitTests/neo.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>

<ItemGroup>
<Folder Include="Oracle\" />
</ItemGroup>
</Project>