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

Test OracleService #3475

Merged
merged 5 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
22 changes: 11 additions & 11 deletions src/Plugins/OracleService/OracleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class OracleService : Plugin, ICommittingHandler, IServiceAddedHandler, I
private readonly ConcurrentDictionary<ulong, OracleTask> pendingQueue = new ConcurrentDictionary<ulong, OracleTask>();
private readonly ConcurrentDictionary<ulong, DateTime> finishedCache = new ConcurrentDictionary<ulong, DateTime>();
private Timer timer;
private readonly CancellationTokenSource cancelSource = new CancellationTokenSource();
public readonly CancellationTokenSource cancelSource = new CancellationTokenSource();
shargon marked this conversation as resolved.
Show resolved Hide resolved
private OracleStatus status = OracleStatus.Unstarted;
private IWalletProvider walletProvider;
private int counter;
Expand Down Expand Up @@ -123,25 +123,25 @@ private void OnStart()
Start(walletProvider?.GetWallet());
}

public void Start(Wallet wallet)
public Task Start(Wallet wallet)
{
if (status == OracleStatus.Running) return;
if (status == OracleStatus.Running) return null;

if (wallet is null)
{
ConsoleHelper.Warning("Please open wallet first!");
return;
return null;
shargon marked this conversation as resolved.
Show resolved Hide resolved
}

if (!CheckOracleAvaiblable(_system.StoreView, out ECPoint[] oracles))
if (!CheckOracleAvailable(_system.StoreView, out ECPoint[] oracles))
{
ConsoleHelper.Warning("The oracle service is unavailable");
return;
return null;
}
if (!CheckOracleAccount(wallet, oracles))
{
ConsoleHelper.Warning("There is no oracle account in wallet");
return;
return null;
}

this.wallet = wallet;
Expand All @@ -150,7 +150,7 @@ public void Start(Wallet wallet)
status = OracleStatus.Running;
timer = new Timer(OnTimer, null, RefreshIntervalMilliSeconds, Timeout.Infinite);
ConsoleHelper.Info($"Oracle started");
ProcessRequestsAsync();
return ProcessRequestsAsync();
}

[ConsoleCommand("stop oracle", Category = "Oracle", Description = "Stop oracle service")]
Expand Down Expand Up @@ -180,7 +180,7 @@ void ICommittingHandler.Blockchain_Committing_Handler(NeoSystem system, Block bl
OnStart();
}
if (status != OracleStatus.Running) return;
if (!CheckOracleAvaiblable(snapshot, out ECPoint[] oracles) || !CheckOracleAccount(wallet, oracles))
if (!CheckOracleAvailable(snapshot, out ECPoint[] oracles) || !CheckOracleAccount(wallet, oracles))
OnStop();
}

Expand Down Expand Up @@ -325,7 +325,7 @@ private async Task ProcessRequestAsync(DataCache snapshot, OracleRequest req)
}
}

private async void ProcessRequestsAsync()
private async Task ProcessRequestsAsync()
{
while (!cancelSource.IsCancellationRequested)
{
Expand Down Expand Up @@ -553,7 +553,7 @@ private bool CheckTxSign(DataCache snapshot, Transaction tx, ConcurrentDictionar
return false;
}

private static bool CheckOracleAvaiblable(DataCache snapshot, out ECPoint[] oracles)
private static bool CheckOracleAvailable(DataCache snapshot, out ECPoint[] oracles)
{
uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1;
oracles = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height);
Expand Down
3 changes: 3 additions & 0 deletions src/Plugins/OracleService/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Akka.Util.Internal;
using Microsoft.Extensions.Configuration;
using System;
using System.Linq;
Expand Down Expand Up @@ -59,6 +60,8 @@ private Settings(IConfigurationSection section) : base(section)
MaxOracleTimeout = TimeSpan.FromMilliseconds(section.GetValue("MaxOracleTimeout", 15000));
AllowPrivateHost = section.GetValue("AllowPrivateHost", false);
AllowedContentTypes = section.GetSection("AllowedContentTypes").GetChildren().Select(p => p.Get<string>()).ToArray();
if (AllowedContentTypes.Count() == 0)
AllowedContentTypes = AllowedContentTypes.Concat("application/json").ToArray();
Https = new HttpsSettings(section.GetSection("Https"));
NeoFS = new NeoFSSettings(section.GetSection("NeoFS"));
AutoStart = section.GetValue("AutoStart", false);
Expand Down
104 changes: 104 additions & 0 deletions tests/Neo.Plugins.OracleService.Tests/E2E_Https.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// UT_OracleService.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Akka.Actor;
using Akka.TestKit.Xunit2;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Cryptography;
using Neo.Cryptography.ECC;
using Neo.Network.P2P.Payloads;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM;
using Neo.Wallets;
using System;
using System.Linq;
using System.Threading.Tasks;
using static Neo.Plugins.OracleService.Tests.TestBlockchain;
using static Neo.Plugins.OracleService.Tests.TestUtils;

namespace Neo.Plugins.OracleService.Tests
{
[TestClass]
public class E2E_Https : TestKit
{
UInt160 customContract;

[TestInitialize]
public void TestSetup()
{
customContract = InitializeContract();
}

[TestMethod]
public void TestE2EHttps()
{
byte[] script;
using (ScriptBuilder sb = new())
{
sb.EmitDynamicCall(NativeContract.RoleManagement.Hash, "designateAsRole",
[Role.Oracle,
new ContractParameter()
{
Type = ContractParameterType.Array,
Value = settings.StandbyCommittee.Select(
p => new ContractParameter() { Type = ContractParameterType.PublicKey, Value = p }).ToList()
}]);
// Expected result: 12685221
sb.EmitDynamicCall(customContract, "createRequest",
["https://api.github.com/orgs/neo-project", "$.id", "callback", new byte[] { }, 1_0000_0000]);
script = sb.ToArray();
}
Transaction[] txs = [
new Transaction
{
Nonce = 233,
ValidUntilBlock = NativeContract.Ledger.CurrentIndex(s_theNeoSystem.GetSnapshotCache()) + s_theNeoSystem.Settings.MaxValidUntilBlockIncrement,
Signers = [new Signer() { Account = MultisigScriptHash, Scopes = WitnessScope.CalledByEntry }],
Attributes = Array.Empty<TransactionAttribute>(),
Script = script,
NetworkFee = 1000_0000,
SystemFee = 2_0000_0000,
}
];
byte[] signature = txs[0].Sign(s_walletAccount.GetKey(), settings.Network);
txs[0].Witnesses = [new Witness
{
InvocationScript = new byte[] { (byte)OpCode.PUSHDATA1, (byte)signature.Length }.Concat(signature).ToArray(),
VerificationScript = MultisigScript,
}];
Block block = new Block
{
Header = new Header
{
Version = 0,
PrevHash = s_theNeoSystem.GenesisBlock.Hash,
Timestamp = s_theNeoSystem.GenesisBlock.Timestamp + 15_000,
Index = 1,
NextConsensus = s_theNeoSystem.GenesisBlock.NextConsensus,
},
Transactions = txs,
};
block.Header.MerkleRoot ??= MerkleTree.ComputeRoot(block.Transactions.Select(t => t.Hash).ToArray());
signature = block.Sign(s_walletAccount.GetKey(), settings.Network);
block.Header.Witness = new Witness
{
InvocationScript = new byte[] { (byte)OpCode.PUSHDATA1, (byte)signature.Length }.Concat(signature).ToArray(),
VerificationScript = MultisigScript,
};
s_theNeoSystem.Blockchain.Ask(block).Wait();
Task t = s_oracle.Start(s_wallet);
t.Wait(TimeSpan.FromMilliseconds(900));
s_oracle.cancelSource.Cancel();
t.Wait();
}
}
}
62 changes: 57 additions & 5 deletions tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,83 @@

using Akka.Actor;
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM;
using Neo.VM.Types;
using Neo.Wallets;
using Neo.Wallets.NEP6;
using System;

namespace Neo.Plugins.OracleService.Tests
{
public static class TestBlockchain
{
private static readonly NeoSystem s_theNeoSystem;
private static readonly MemoryStore s_store = new();
public static readonly NeoSystem s_theNeoSystem;
public static readonly MemoryStore s_store = new();
public static readonly NEP6Wallet s_wallet;
public static readonly WalletAccount s_walletAccount;
public static readonly OracleService s_oracle;

private class StoreProvider : IStoreProvider
{
public string Name => "TestProvider";

public IStore GetStore(string path) => s_store;
}

static TestBlockchain()
{
Console.WriteLine("initialize NeoSystem");
s_theNeoSystem = new NeoSystem(ProtocolSettings.Load("config.json"), new StoreProvider());
StoreProvider _memoryStoreProvider = new();
s_oracle = new();
s_theNeoSystem = new NeoSystem(TestUtils.settings, _memoryStoreProvider);
s_wallet = TestUtils.GenerateTestWallet("123");
s_walletAccount = s_wallet.Import("KxuRSsHgJMb3AMSN6B9P3JHNGMFtxmuimqgR9MmXPcv3CLLfusTd");
}

public static void InitializeMockNeoSystem()
public static UInt160 InitializeContract()
{
string _oracleContractSrc = """
using System.Numerics;using Neo.SmartContract.Framework;using Neo.SmartContract.Framework.Native;using Neo.SmartContract.Framework.Services;
namespace oracle_demo{public class OracleDemo:SmartContract{
const byte PREFIX_COUNT = 0xcc;
const byte PREFIX_DATA = 0xdd;
public static string GetRequstData() => Storage.Get(Storage.CurrentContext, new byte[] { PREFIX_DATA });
public static BigInteger GetRequstCount() => (BigInteger)Storage.Get(Storage.CurrentContext, new byte[] { PREFIX_COUNT });
public static void CreateRequest(string url, string filter, string callback, byte[] userData, long gasForResponse) => Oracle.Request(url, filter, callback, userData, gasForResponse);
public static void Callback(string url, byte[] userData, int code, byte[] result)
{
ExecutionEngine.Assert(Runtime.CallingScriptHash == Oracle.Hash, "Unauthorized!");
StorageContext currentContext = Storage.CurrentContext;
Storage.Put(currentContext, new byte[] { PREFIX_DATA }, (ByteString)result);
Storage.Put(currentContext, new byte[] { PREFIX_COUNT },
(BigInteger)Storage.Get(currentContext, new byte[] { PREFIX_DATA }) + 1);
}}}
""";
string base64NefFile = "TkVGM05lby5Db21waWxlci5DU2hhcnAgMy43LjQrNjAzNGExODIxY2E3MDk0NjBlYzMxMzZjNzBjMmRjYzNiZWEuLi4AAAFYhxcRfgqoEHKvq3HS3Yn+fEuS/gdyZXF1ZXN0BQAADwAAmAwB3dswQZv2Z85Bkl3oMUAMAczbMEGb9mfOQZJd6DFK2CYERRDbIUBXAAV8e3p5eDcAAEBXAQRBOVNuPAwUWIcXEX4KqBByr6tx0t2J/nxLkv6XDA1VbmF1dGhvcml6ZWQh4UGb9mfOcHvbKAwB3dswaEHmPxiEDAHd2zBoQZJd6DFK2CYERRDbIRGeDAHM2zBoQeY/GIRAnIyFhg==";
string manifest = """{"name":"OracleDemo","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"getRequstData","parameters":[],"returntype":"String","offset":0,"safe":false},{"name":"getRequstCount","parameters":[],"returntype":"Integer","offset":16,"safe":false},{"name":"createRequest","parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"callback","type":"String"},{"name":"userData","type":"ByteArray"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","offset":40,"safe":false},{"name":"callback","parameters":[{"name":"url","type":"String"},{"name":"userData","type":"ByteArray"},{"name":"code","type":"Integer"},{"name":"result","type":"ByteArray"}],"returntype":"Void","offset":52,"safe":false}],"events":[]},"permissions":[{"contract":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","methods":["request"]}],"trusts":[],"extra":{"nef":{"optimization":"All"}}}""";
byte[] script;
using (ScriptBuilder sb = new())
{
sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", Convert.FromBase64String(base64NefFile), manifest);
script = sb.ToArray();
}
SnapshotCache snapshot = s_theNeoSystem.GetSnapshotCache();
Transaction? tx = new Transaction
{
Nonce = 233,
ValidUntilBlock = NativeContract.Ledger.CurrentIndex(snapshot) + s_theNeoSystem.Settings.MaxValidUntilBlockIncrement,
Signers = [new Signer() { Account = TestUtils.ValidatorScriptHash, Scopes = WitnessScope.CalledByEntry }],
Attributes = System.Array.Empty<TransactionAttribute>(),
Script = script,
Witnesses = null,
};
var engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: s_theNeoSystem.Settings, gas: 1200_0000_0000);
engine.SnapshotCache.Commit();
var result = (Neo.VM.Types.Array)engine.ResultStack.Peek();
return new UInt160(result[2].GetSpan());
}

internal static void ResetStore()
Expand Down
25 changes: 25 additions & 0 deletions tests/Neo.Plugins.OracleService.Tests/TestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,27 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using FluentAssertions;
using Neo.IO;
using Neo.Json;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.Wallets;
using Neo.Wallets.NEP6;
using System;

namespace Neo.Plugins.OracleService.Tests
{
public static class TestUtils
{
public static readonly ProtocolSettings settings = ProtocolSettings.Load("config.json");
public static readonly byte[] ValidatorScript = Contract.CreateSignatureRedeemScript(settings.StandbyCommittee[0]);
public static readonly UInt160 ValidatorScriptHash = ValidatorScript.ToScriptHash();
public static readonly string ValidatorAddress = ValidatorScriptHash.ToAddress(ProtocolSettings.Default.AddressVersion);
public static readonly byte[] MultisigScript = Contract.CreateMultiSigRedeemScript(1, settings.StandbyCommittee);
public static readonly UInt160 MultisigScriptHash = MultisigScript.ToScriptHash();
public static readonly string MultisigAddress = MultisigScriptHash.ToAddress(ProtocolSettings.Default.AddressVersion);

public static StorageKey CreateStorageKey(this NativeContract contract, byte prefix, ISerializable key)
{
var k = new KeyBuilder(contract.Id, prefix);
Expand All @@ -28,5 +41,17 @@ public static StorageKey CreateStorageKey(this NativeContract contract, byte pre
{
return new KeyBuilder(contract.Id, prefix).AddBigEndian(value);
}

public static NEP6Wallet GenerateTestWallet(string password)
{
JObject wallet = new JObject();
wallet["name"] = "noname";
wallet["version"] = new Version("1.0").ToString();
wallet["scrypt"] = new ScryptParameters(2, 1, 1).ToJson();
wallet["accounts"] = new JArray();
wallet["extra"] = null;
wallet.ToString().Should().Be("{\"name\":\"noname\",\"version\":\"1.0\",\"scrypt\":{\"n\":2,\"r\":1,\"p\":1},\"accounts\":[],\"extra\":null}");
return new NEP6Wallet(null, password, settings, wallet);
}
}
}
6 changes: 0 additions & 6 deletions tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ namespace Neo.Plugins.OracleService.Tests
[TestClass]
public class UT_OracleService : TestKit
{
[TestInitialize]
public void TestSetup()
{
TestBlockchain.InitializeMockNeoSystem();
}

[TestMethod]
public void TestFilter()
{
Expand Down
26 changes: 3 additions & 23 deletions tests/Neo.Plugins.OracleService.Tests/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
}
},
"ProtocolConfiguration": {
"Network": 860833102,
"Network": 5195086,
"AddressVersion": 53,
"MillisecondsPerBlock": 15000,
"MaxTransactionsPerBlock": 512,
Expand All @@ -39,29 +39,9 @@
"HF_Basilisk": 4120000
},
"InitialGasDistribution": 5200000000000000,
"ValidatorsCount": 7,
"ValidatorsCount": 1,
shargon marked this conversation as resolved.
Show resolved Hide resolved
"StandbyCommittee": [
"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c",
"02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093",
"03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a",
"02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554",
"024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d",
"02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e",
"02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70",
"023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe",
"03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379",
"03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050",
"03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0",
"02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62",
"03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0",
"0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654",
"020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639",
"0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30",
"03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde",
"02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad",
"0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d",
"03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc",
"02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a"
"0278ed78c917797b637a7ed6e7a9d94e8c408444c41ee4c0a0f310a256b9271eda"
],
"SeedList": [
"seed1.neo.org:10333",
Expand Down
Loading