Skip to content

Commit

Permalink
contract invoke --results needs a mechanism to specify signers (#147)
Browse files Browse the repository at this point in the history
* contract invoke --results needs a mechanism to specify signers
Fixes #146

* TestApplicationEngine.CreateTestTransaction

* update CI scripts

* remove nbgv version from release CI yml

* BlockchainToolkit3 Version

Co-authored-by: Harry <[email protected]>
  • Loading branch information
devhawk and Harry authored Jun 15, 2021
1 parent ed990c1 commit e62452f
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 51 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ jobs:
fetch-depth: 0
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
- name: Install nbgv
run: dotnet tool install nbgv --tool-path ./tools --version 3.3.37
run: dotnet tool install nbgv --tool-path ./tools
- name: Run nbgv
run: echo "NUGET_PACKAGE_VERSION=$(./tools/nbgv get-version -v NuGetPackageVersion)" >> $GITHUB_ENV
- name: Install dependencies
Expand Down
2 changes: 1 addition & 1 deletion eng/azure-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ steps:
displayName: 'use .NET Core SDK from global.json'
inputs:
packageType: 'sdk'
useGlobalJson: true
version: '5.0.x'

- task: DotNetCoreCLI@2
displayName: 'dotnet pack'
Expand Down
2 changes: 1 addition & 1 deletion src/neoxp/Commands/ContractCommand.Invoke.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ internal async Task<int> OnExecuteAsync(IConsole console)
if (Results)
{
using var txExec = txExecutorFactory.Create(chainManager, Trace, Json);
await txExec.InvokeForResultsAsync(InvocationFile);
await txExec.InvokeForResultsAsync(InvocationFile, Account, WitnessScope);
}
else
{
Expand Down
14 changes: 9 additions & 5 deletions src/neoxp/Extensions/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Threading.Tasks;
using Neo;
using Neo.Network.P2P.Payloads;
using Neo.Network.RPC;
using Neo.Network.RPC.Models;
using Neo.Persistence;
Expand All @@ -18,12 +19,15 @@ static class Extensions

public static IEnumerable<WalletAccount> GetMultiSigAccounts(this Wallet wallet) => wallet.GetAccounts().Where(IsMultiSigContract);

public static ApplicationEngine Invoke(this Neo.VM.ScriptBuilder builder, ProtocolSettings settings, DataCache snapshot) => Invoke(builder.ToArray(), settings, snapshot);
public static ApplicationEngine Invoke(this Neo.VM.ScriptBuilder builder, ProtocolSettings settings, DataCache snapshot, IVerifiable? container = null)
=> Invoke(builder.ToArray(), settings, snapshot, container);

public static ApplicationEngine Invoke(this Neo.VM.Script script, ProtocolSettings settings, DataCache snapshot) => ApplicationEngine.Run(
script: script,
snapshot: snapshot,
settings: settings);
public static ApplicationEngine Invoke(this Neo.VM.Script script, ProtocolSettings settings, DataCache snapshot, IVerifiable? container = null)
=> ApplicationEngine.Run(
script: script,
snapshot: snapshot,
settings: settings,
container: container);

public static async Task WriteTxHashAsync(this TextWriter writer, UInt256 txHash, string txType = "", bool json = false)
{
Expand Down
2 changes: 1 addition & 1 deletion src/neoxp/IExpressNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ enum CheckpointMode { Online, Offline }

Task<CheckpointMode> CreateCheckpointAsync(string checkPointPath);

Task<RpcInvokeResult> InvokeAsync(Script script);
Task<RpcInvokeResult> InvokeAsync(Script script, Signer? signer = null);
Task<UInt256> ExecuteAsync(Wallet wallet, UInt160 accountHash, WitnessScope witnessScope, Script script, decimal additionalGas = 0);
Task<UInt256> SubmitOracleResponseAsync(OracleResponse response, IReadOnlyList<ECPoint> oracleNodes);

Expand Down
2 changes: 1 addition & 1 deletion src/neoxp/ITransactionExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface ITransactionExecutor : IDisposable
IExpressNode ExpressNode { get; }
Task ContractDeployAsync(string contract, string account, string password, WitnessScope witnessScope, bool force);
Task ContractInvokeAsync(string invocationFile, string account, string password, WitnessScope witnessScope);
Task InvokeForResultsAsync(string invocationFile);
Task InvokeForResultsAsync(string invocationFile, string account, WitnessScope witnessScope);
Task TransferAsync(string quantity, string asset, string sender, string password, string receiver);
Task OracleEnableAsync(string account, string password);
Task OracleResponseAsync(string url, string responsePath, ulong? requestId = null);
Expand Down
6 changes: 4 additions & 2 deletions src/neoxp/Node/OfflineNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Neo;
using Neo.BlockchainToolkit.Models;
using Neo.BlockchainToolkit.Persistence;
using Neo.BlockchainToolkit.SmartContract;
using Neo.Cryptography;
using Neo.Cryptography.ECC;
using Neo.IO;
Expand Down Expand Up @@ -104,13 +105,14 @@ private void OnLog(object sender, LogEventArgs args)
}
}

public Task<RpcInvokeResult> InvokeAsync(Neo.VM.Script script)
public Task<RpcInvokeResult> InvokeAsync(Neo.VM.Script script, Signer? signer = null)
{
try
{
if (disposedValue) return Task.FromException<RpcInvokeResult>(new ObjectDisposedException(nameof(OfflineNode)));

using ApplicationEngine engine = script.Invoke(neoSystem.Settings, neoSystem.StoreView);
Transaction tx = TestApplicationEngine.CreateTestTransaction(signer);
using ApplicationEngine engine = script.Invoke(neoSystem.Settings, neoSystem.StoreView, tx);
return Task.FromResult(new RpcInvokeResult()
{
State = engine.State,
Expand Down
6 changes: 4 additions & 2 deletions src/neoxp/Node/OnlineNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ public void Dispose()
return IExpressNode.CheckpointMode.Online;
}

public Task<RpcInvokeResult> InvokeAsync(Script script)
public Task<RpcInvokeResult> InvokeAsync(Script script, Signer? signer = null)
{
return rpcClient.InvokeScriptAsync(script);
return signer == null
? rpcClient.InvokeScriptAsync(script)
: rpcClient.InvokeScriptAsync(script, signer);
}

public async Task<UInt256> ExecuteAsync(Wallet wallet, UInt160 accountHash, WitnessScope witnessScope, Script script, decimal additionalGas = 0)
Expand Down
84 changes: 48 additions & 36 deletions src/neoxp/TransactionExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,27 @@ public async Task ContractInvokeAsync(string invocationFile, string accountName,
await writer.WriteTxHashAsync(txHash, "Deployment", json).ConfigureAwait(false);
}

public async Task InvokeForResultsAsync(string invocationFile)
public async Task InvokeForResultsAsync(string invocationFile, string accountName, WitnessScope witnessScope)
{
if (!fileSystem.File.Exists(invocationFile))
{
throw new Exception($"Invocation file {invocationFile} couldn't be found");
}

Signer? signer = TryGetSigningAccount(accountName, string.Empty, out _, out var accountHash)
? signer = new Signer
{
Account = accountHash,
Scopes = witnessScope,
AllowedContracts = Array.Empty<UInt160>(),
AllowedGroups = Array.Empty<Neo.Cryptography.ECC.ECPoint>()
}
: null;

var parser = await expressNode.GetContractParameterParserAsync(chainManager).ConfigureAwait(false);
var script = await parser.LoadInvocationScriptAsync(invocationFile).ConfigureAwait(false);

var result = await expressNode.InvokeAsync(script).ConfigureAwait(false);
var result = await expressNode.InvokeAsync(script, signer).ConfigureAwait(false);
if (json)
{
await writer.WriteLineAsync(result.ToJson().ToString(true)).ConfigureAwait(false);
Expand All @@ -100,7 +110,7 @@ public async Task InvokeForResultsAsync(string invocationFile)
{
await writer.WriteLineAsync($"VM State: {result.State}").ConfigureAwait(false);
await writer.WriteLineAsync($"Gas Consumed: {result.GasConsumed}").ConfigureAwait(false);
if (result.Exception != null)
if (!string.IsNullOrEmpty(result.Exception))
{
await writer.WriteLineAsync($"Expception: {result.Exception}").ConfigureAwait(false);
}
Expand Down Expand Up @@ -257,53 +267,55 @@ static OneOf<decimal, All> ParseQuantity(string quantity)

bool TryGetSigningAccount(string name, string password, [MaybeNullWhen(false)] out Wallet wallet, [MaybeNullWhen(false)] out UInt160 accountHash)
{
var settings = chainManager.Chain.GetProtocolSettings();

if (name.Equals(ExpressChainExtensions.GENESIS, StringComparison.OrdinalIgnoreCase))
if (!string.IsNullOrEmpty(name))
{
(wallet, accountHash) = chainManager.Chain.GetGenesisAccount(settings);
return true;
}
var settings = chainManager.Chain.GetProtocolSettings();

if (chainManager.Chain.Wallets != null && chainManager.Chain.Wallets.Count > 0)
{
for (int i = 0; i < chainManager.Chain.Wallets.Count; i++)
if (name.Equals(ExpressChainExtensions.GENESIS, StringComparison.OrdinalIgnoreCase))
{
var expWallet = chainManager.Chain.Wallets[i];
if (name.Equals(expWallet.Name, StringComparison.OrdinalIgnoreCase))
{
wallet = DevWallet.FromExpressWallet(settings, expWallet);
accountHash = wallet.GetAccounts().Single(a => a.IsDefault).ScriptHash;
return true;
}
(wallet, accountHash) = chainManager.Chain.GetGenesisAccount(settings);
return true;
}
}

for (int i = 0; i < chainManager.Chain.ConsensusNodes.Count; i++)
{
var expWallet = chainManager.Chain.ConsensusNodes[i].Wallet;
if (name.Equals(expWallet.Name, StringComparison.OrdinalIgnoreCase))
if (chainManager.Chain.Wallets != null && chainManager.Chain.Wallets.Count > 0)
{
wallet = DevWallet.FromExpressWallet(settings, expWallet);
accountHash = wallet.GetAccounts().Single(a => !a.Contract.Script.IsMultiSigContract()).ScriptHash;
return true;
for (int i = 0; i < chainManager.Chain.Wallets.Count; i++)
{
var expWallet = chainManager.Chain.Wallets[i];
if (name.Equals(expWallet.Name, StringComparison.OrdinalIgnoreCase))
{
wallet = DevWallet.FromExpressWallet(settings, expWallet);
accountHash = wallet.GetAccounts().Single(a => a.IsDefault).ScriptHash;
return true;
}
}
}
}

if (!string.IsNullOrEmpty(password))
{
if (TryGetNEP2Wallet(name, password, settings, out wallet, out accountHash))
for (int i = 0; i < chainManager.Chain.ConsensusNodes.Count; i++)
{
return true;
var expWallet = chainManager.Chain.ConsensusNodes[i].Wallet;
if (name.Equals(expWallet.Name, StringComparison.OrdinalIgnoreCase))
{
wallet = DevWallet.FromExpressWallet(settings, expWallet);
accountHash = wallet.GetAccounts().Single(a => !a.Contract.Script.IsMultiSigContract()).ScriptHash;
return true;
}
}

if (TryGetNEP6Wallet(name, password, settings, out wallet, out accountHash))
if (!string.IsNullOrEmpty(password))
{
return true;
if (TryGetNEP2Wallet(name, password, settings, out wallet, out accountHash))
{
return true;
}

if (TryGetNEP6Wallet(name, password, settings, out wallet, out accountHash))
{
return true;
}
}
}


wallet = null;
accountHash = null;
return false;
Expand Down Expand Up @@ -332,7 +344,7 @@ static bool TryGetNEP6Wallet(string path, string password, ProtocolSettings sett
{
var nep6wallet = new Neo.Wallets.NEP6.NEP6Wallet(path, settings);
using var unlock = nep6wallet.Unlock(password);
var nep6account = nep6wallet.GetAccounts().SingleOrDefault(a => a.IsDefault)
var nep6account = nep6wallet.GetAccounts().SingleOrDefault(a => a.IsDefault)
?? nep6wallet.GetAccounts().SingleOrDefault()
?? throw new InvalidOperationException("Neo-express only supports NEP-6 wallets with a single default account or a single account");
if (nep6account.IsMultiSigContract()) throw new Exception("Neo-express doesn't supports multi-sig NEP-6 accounts");
Expand Down
2 changes: 1 addition & 1 deletion src/neoxp/neoxp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
</PackageReference>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="3.1.0"/>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
<PackageReference Include="Neo.BlockchainToolkit3" Version="1.0.47-preview"/>
<PackageReference Include="Neo.BlockchainToolkit3" Version="1.0.51-preview"/>
<PackageReference Include="Neo.Consensus.DBFT" Version="$(NeoVersion)"/>
<PackageReference Include="Neo.Network.RPC.RpcClient" Version="$(NeoVersion)"/>
<PackageReference Include="Neo.Plugins.RpcServer" Version="$(NeoVersion)"/>
Expand Down

0 comments on commit e62452f

Please sign in to comment.