Skip to content

Commit e018bc3

Browse files
Hecate2shargon
andauthored
test GetApplicationLog (#3470)
* test GetApplicationLog * filter execution type * Test_Commands; refactor * apply review suggestions --------- Co-authored-by: Shargon <shargon@gmail.com>
1 parent 5fe5462 commit e018bc3

File tree

3 files changed

+221
-7
lines changed

3 files changed

+221
-7
lines changed

src/Plugins/ApplicationLogs/LogReader.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class LogReader : Plugin, ICommittingHandler, ICommittedHandler, ILogHand
3030
{
3131
#region Globals
3232

33-
private NeoStore _neostore;
33+
internal NeoStore _neostore;
3434
private NeoSystem _neosystem;
3535
private readonly List<LogEventArgs> _logEvents;
3636

@@ -123,7 +123,7 @@ public JToken GetApplicationLog(JArray _params)
123123
#region Console Commands
124124

125125
[ConsoleCommand("log block", Category = "ApplicationLog Commands")]
126-
private void OnGetBlockCommand(string blockHashOrIndex, string eventName = null)
126+
internal void OnGetBlockCommand(string blockHashOrIndex, string eventName = null)
127127
{
128128
UInt256 blockhash;
129129
if (uint.TryParse(blockHashOrIndex, out var blockIndex))
@@ -154,7 +154,7 @@ private void OnGetBlockCommand(string blockHashOrIndex, string eventName = null)
154154
}
155155

156156
[ConsoleCommand("log tx", Category = "ApplicationLog Commands")]
157-
private void OnGetTransactionCommand(UInt256 txhash, string eventName = null)
157+
internal void OnGetTransactionCommand(UInt256 txhash, string eventName = null)
158158
{
159159
var txApplication = string.IsNullOrEmpty(eventName) ?
160160
_neostore.GetTransactionLog(txhash) :
@@ -167,7 +167,7 @@ private void OnGetTransactionCommand(UInt256 txhash, string eventName = null)
167167
}
168168

169169
[ConsoleCommand("log contract", Category = "ApplicationLog Commands")]
170-
private void OnGetContractCommand(UInt160 scripthash, uint page = 1, uint pageSize = 1, string eventName = null)
170+
internal void OnGetContractCommand(UInt160 scripthash, uint page = 1, uint pageSize = 1, string eventName = null)
171171
{
172172
if (page == 0)
173173
{

tests/Neo.Plugins.ApplicationLogs.Tests/Neo.Plugins.ApplicationLogs.Tests.csproj

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
10-
<PackageReference Include="xunit" Version="2.5.3" />
11-
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
9+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
10+
<PackageReference Include="xunit" Version="2.8.1" />
11+
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1" />
1212
</ItemGroup>
1313

1414
<ItemGroup>
1515
<ProjectReference Include="..\..\src\Plugins\ApplicationLogs\ApplicationLogs.csproj" />
1616
<ProjectReference Include="..\..\src\Plugins\RocksDBStore\RocksDBStore.csproj" />
17+
<ProjectReference Include="..\Neo.UnitTests\Neo.UnitTests.csproj" />
1718
</ItemGroup>
1819

1920
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// Copyright (C) 2015-2024 The Neo Project.
2+
//
3+
// UT_ApplicationLogs.cs file belongs to the neo project and is free
4+
// software distributed under the MIT software license, see the
5+
// accompanying file LICENSE in the main directory of the
6+
// repository or http://www.opensource.org/licenses/mit-license.php
7+
// for more details.
8+
//
9+
// Redistribution and use in source and binary forms with or without
10+
// modifications are permitted.
11+
12+
using Akka.Actor;
13+
using Akka.Util;
14+
using Microsoft.AspNetCore.Authorization;
15+
using Neo.Cryptography;
16+
using Neo.IO;
17+
using Neo.Json;
18+
using Neo.Ledger;
19+
using Neo.Network.P2P.Payloads;
20+
using Neo.Persistence;
21+
using Neo.Plugins.ApplicationLogs;
22+
using Neo.Plugins.ApplicationLogs.Store;
23+
using Neo.Plugins.ApplicationLogs.Store.Models;
24+
using Neo.Plugins.ApplicationLogs.Store.States;
25+
using Neo.Plugins.ApplicationsLogs.Tests.Setup;
26+
using Neo.SmartContract;
27+
using Neo.SmartContract.Native;
28+
using Neo.UnitTests;
29+
using Neo.UnitTests.Extensions;
30+
using Neo.VM;
31+
using Neo.Wallets;
32+
using Neo.Wallets.NEP6;
33+
using System;
34+
using System.Collections.Generic;
35+
using System.Linq;
36+
using System.Security.Policy;
37+
using System.Text;
38+
using System.Threading.Tasks;
39+
using Xunit;
40+
using static Neo.Plugins.ApplicationsLogs.Tests.UT_LogReader;
41+
42+
namespace Neo.Plugins.ApplicationsLogs.Tests
43+
{
44+
public class UT_LogReader : IClassFixture<NeoSystemFixture>
45+
{
46+
static readonly string NeoTransferScript = "CxEMFPlu76Cuc\u002BbgteStE4ozsOWTNUdrDBQtYNweHko3YcnMFOes3ceblcI/lRTAHwwIdHJhbnNmZXIMFPVj6kC8KD1NDgXEjqMFs/Kgc0DvQWJ9W1I=";
47+
static readonly byte[] ValidatorScript = Contract.CreateSignatureRedeemScript(TestProtocolSettings.SoleNode.StandbyCommittee[0]);
48+
static readonly UInt160 ValidatorScriptHash = ValidatorScript.ToScriptHash();
49+
static readonly string ValidatorAddress = ValidatorScriptHash.ToAddress(ProtocolSettings.Default.AddressVersion);
50+
static readonly byte[] MultisigScript = Contract.CreateMultiSigRedeemScript(1, TestProtocolSettings.SoleNode.StandbyCommittee);
51+
static readonly UInt160 MultisigScriptHash = MultisigScript.ToScriptHash();
52+
static readonly string MultisigAddress = MultisigScriptHash.ToAddress(ProtocolSettings.Default.AddressVersion);
53+
54+
public class TestMemoryStoreProvider(MemoryStore memoryStore) : IStoreProvider
55+
{
56+
public MemoryStore MemoryStore { get; init; } = memoryStore;
57+
public string Name => nameof(MemoryStore);
58+
public IStore GetStore(string path) => MemoryStore;
59+
}
60+
61+
public class NeoSystemFixture : IDisposable
62+
{
63+
public NeoSystem _neoSystem;
64+
public TestMemoryStoreProvider _memoryStoreProvider;
65+
public MemoryStore _memoryStore;
66+
public readonly NEP6Wallet _wallet = TestUtils.GenerateTestWallet("123");
67+
public WalletAccount _walletAccount;
68+
public Transaction[] txs;
69+
public Block block;
70+
public LogReader logReader;
71+
72+
public NeoSystemFixture()
73+
{
74+
_memoryStore = new MemoryStore();
75+
_memoryStoreProvider = new TestMemoryStoreProvider(_memoryStore);
76+
logReader = new LogReader();
77+
Plugin.Plugins.Add(logReader); // initialize before NeoSystem to let NeoSystem load the plugin
78+
_neoSystem = new NeoSystem(TestProtocolSettings.SoleNode with { Network = ApplicationLogs.Settings.Default.Network }, _memoryStoreProvider);
79+
_walletAccount = _wallet.Import("KxuRSsHgJMb3AMSN6B9P3JHNGMFtxmuimqgR9MmXPcv3CLLfusTd");
80+
81+
NeoSystem system = _neoSystem;
82+
txs = [
83+
new Transaction
84+
{
85+
Nonce = 233,
86+
ValidUntilBlock = NativeContract.Ledger.CurrentIndex(system.GetSnapshotCache()) + system.Settings.MaxValidUntilBlockIncrement,
87+
Signers = [new Signer() { Account = MultisigScriptHash, Scopes = WitnessScope.CalledByEntry }],
88+
Attributes = Array.Empty<TransactionAttribute>(),
89+
Script = Convert.FromBase64String(NeoTransferScript),
90+
NetworkFee = 1000_0000,
91+
SystemFee = 1000_0000,
92+
}
93+
];
94+
byte[] signature = txs[0].Sign(_walletAccount.GetKey(), ApplicationLogs.Settings.Default.Network);
95+
txs[0].Witnesses = [new Witness
96+
{
97+
InvocationScript = new byte[] { (byte)OpCode.PUSHDATA1, (byte)signature.Length }.Concat(signature).ToArray(),
98+
VerificationScript = MultisigScript,
99+
}];
100+
block = new Block
101+
{
102+
Header = new Header
103+
{
104+
Version = 0,
105+
PrevHash = _neoSystem.GenesisBlock.Hash,
106+
MerkleRoot = new UInt256(),
107+
Timestamp = _neoSystem.GenesisBlock.Timestamp + 15_000,
108+
Index = 1,
109+
NextConsensus = _neoSystem.GenesisBlock.NextConsensus,
110+
},
111+
Transactions = txs,
112+
};
113+
block.Header.MerkleRoot ??= MerkleTree.ComputeRoot(block.Transactions.Select(t => t.Hash).ToArray());
114+
signature = block.Sign(_walletAccount.GetKey(), ApplicationLogs.Settings.Default.Network);
115+
block.Header.Witness = new Witness
116+
{
117+
InvocationScript = new byte[] { (byte)OpCode.PUSHDATA1, (byte)signature.Length }.Concat(signature).ToArray(),
118+
VerificationScript = MultisigScript,
119+
};
120+
}
121+
122+
public void Dispose()
123+
{
124+
logReader.Dispose();
125+
_neoSystem.Dispose();
126+
_memoryStore.Dispose();
127+
}
128+
}
129+
130+
private readonly NeoSystemFixture _neoSystemFixture;
131+
132+
public UT_LogReader(NeoSystemFixture neoSystemFixture)
133+
{
134+
_neoSystemFixture = neoSystemFixture;
135+
}
136+
137+
[Fact]
138+
public async Task Test_GetApplicationLog()
139+
{
140+
NeoSystem system = _neoSystemFixture._neoSystem;
141+
Block block = _neoSystemFixture.block;
142+
await system.Blockchain.Ask(block); // persist the block
143+
144+
JObject blockJson = (JObject)_neoSystemFixture.logReader.GetApplicationLog([block.Hash.ToString()]);
145+
Assert.Equal(blockJson["blockhash"], block.Hash.ToString());
146+
JArray executions = (JArray)blockJson["executions"];
147+
Assert.Equal(executions.Count, 2);
148+
Assert.Equal(executions[0]["trigger"], "OnPersist");
149+
Assert.Equal(executions[1]["trigger"], "PostPersist");
150+
JArray notifications = (JArray)executions[1]["notifications"];
151+
Assert.Equal(notifications.Count, 1);
152+
Assert.Equal(notifications[0]["contract"], GasToken.GAS.Hash.ToString());
153+
Assert.Equal(notifications[0]["eventname"], "Transfer"); // from null to Validator
154+
Assert.Equal(notifications[0]["state"]["value"][0]["type"], nameof(ContractParameterType.Any));
155+
Assert.Equal(Convert.FromBase64String(notifications[0]["state"]["value"][1]["value"].AsString()), ValidatorScriptHash.ToArray());
156+
Assert.Equal(notifications[0]["state"]["value"][2]["value"], "50000000");
157+
158+
blockJson = (JObject)_neoSystemFixture.logReader.GetApplicationLog([block.Hash.ToString(), "PostPersist"]);
159+
executions = (JArray)blockJson["executions"];
160+
Assert.Equal(executions.Count, 1);
161+
Assert.Equal(executions[0]["trigger"], "PostPersist");
162+
163+
JObject transactionJson = (JObject)_neoSystemFixture.logReader.GetApplicationLog([_neoSystemFixture.txs[0].Hash.ToString(), true]); // "true" is invalid but still works
164+
executions = (JArray)transactionJson["executions"];
165+
Assert.Equal(executions.Count, 1);
166+
Assert.Equal(executions[0]["vmstate"], nameof(VMState.HALT));
167+
Assert.Equal(executions[0]["stack"][0]["value"], true);
168+
notifications = (JArray)executions[0]["notifications"];
169+
Assert.Equal(notifications.Count, 2);
170+
Assert.Equal(notifications[0]["eventname"].AsString(), "Transfer");
171+
Assert.Equal(notifications[0]["contract"].AsString(), NeoToken.NEO.Hash.ToString());
172+
Assert.Equal(notifications[0]["state"]["value"][2]["value"], "1");
173+
Assert.Equal(notifications[1]["eventname"].AsString(), "Transfer");
174+
Assert.Equal(notifications[1]["contract"].AsString(), GasToken.GAS.Hash.ToString());
175+
Assert.Equal(notifications[1]["state"]["value"][2]["value"], "50000000");
176+
}
177+
178+
[Fact]
179+
public async Task Test_Commands()
180+
{
181+
NeoSystem system = _neoSystemFixture._neoSystem;
182+
Block block = _neoSystemFixture.block;
183+
await system.Blockchain.Ask(block); // persist the block
184+
185+
_neoSystemFixture.logReader.OnGetBlockCommand("1");
186+
_neoSystemFixture.logReader.OnGetBlockCommand(block.Hash.ToString());
187+
_neoSystemFixture.logReader.OnGetContractCommand(NeoToken.NEO.Hash);
188+
_neoSystemFixture.logReader.OnGetTransactionCommand(_neoSystemFixture.txs[0].Hash);
189+
190+
BlockchainExecutionModel blockLog = _neoSystemFixture.logReader._neostore.GetBlockLog(block.Hash, TriggerType.Application);
191+
BlockchainExecutionModel transactionLog = _neoSystemFixture.logReader._neostore.GetTransactionLog(_neoSystemFixture.txs[0].Hash);
192+
foreach (BlockchainExecutionModel log in new BlockchainExecutionModel[] { blockLog, transactionLog })
193+
{
194+
Assert.Equal(log.VmState, VMState.HALT);
195+
Assert.Equal(log.Stack[0].GetBoolean(), true);
196+
Assert.Equal(log.Notifications.Count(), 2);
197+
Assert.Equal(log.Notifications[0].EventName, "Transfer");
198+
Assert.Equal(log.Notifications[0].ScriptHash, NeoToken.NEO.Hash);
199+
Assert.Equal(log.Notifications[0].State[2], 1);
200+
Assert.Equal(log.Notifications[1].EventName, "Transfer");
201+
Assert.Equal(log.Notifications[1].ScriptHash, GasToken.GAS.Hash);
202+
Assert.Equal(log.Notifications[1].State[2], 50000000);
203+
}
204+
205+
List<(BlockchainEventModel eventLog, UInt256 txHash)> neoLogs = _neoSystemFixture.logReader._neostore.GetContractLog(NeoToken.NEO.Hash, TriggerType.Application).ToList();
206+
Assert.Equal(neoLogs.Count, 1);
207+
Assert.Equal(neoLogs[0].txHash, _neoSystemFixture.txs[0].Hash);
208+
Assert.Equal(neoLogs[0].eventLog.EventName, "Transfer");
209+
Assert.Equal(neoLogs[0].eventLog.ScriptHash, NeoToken.NEO.Hash);
210+
Assert.Equal(neoLogs[0].eventLog.State[2], 1);
211+
}
212+
}
213+
}

0 commit comments

Comments
 (0)