Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Added blockchain show block/transactions/contracts commands #905

Merged
merged 22 commits into from
Nov 27, 2023
Merged
Changes from 12 commits
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
242 changes: 242 additions & 0 deletions neo-cli/CLI/MainService.Blockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@
// modifications are permitted.

using Neo.ConsoleService;
using Neo.Json;
using Neo.Network.P2P.Payloads;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Org.BouncyCastle.Asn1.Cms;
using System;
using System.Linq;
using System.Security.Policy;

namespace Neo.CLI
{
Expand Down Expand Up @@ -41,5 +47,241 @@ private void OnExportBlocksStartCountCommand(uint start, uint count = uint.MaxVa

WriteBlocks(start, count, path, true);
}

[ConsoleCommand("show block", Category = "Blockchain Commands")]
private void OnShowBlockCommand(string indexOrHash)
{
Block block = null;

if (uint.TryParse(indexOrHash, out var index))
block = NativeContract.Ledger.GetBlock(_neoSystem.StoreView, index);
else if (UInt256.TryParse(indexOrHash, out var hash))
block = NativeContract.Ledger.GetBlock(_neoSystem.StoreView, hash);
else
{
ConsoleHelper.Error("Enter a valid block index or hash.");
return;
}

if (block is null)
{
ConsoleHelper.Error($"Block {indexOrHash} doesn't exist.");
return;
}

DateTime blockDatetime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
blockDatetime = blockDatetime.AddMilliseconds(block.Timestamp).ToLocalTime();

ConsoleHelper.Info("", "-------------", "Block", "-------------");
ConsoleHelper.Info();
ConsoleHelper.Info("", " Timestamp: ", $"{blockDatetime}");
ConsoleHelper.Info("", " Index: ", $"{block.Index}");
ConsoleHelper.Info("", " Hash: ", $"{block.Hash}");
ConsoleHelper.Info("", " Nonce: ", $"{block.Nonce}");
ConsoleHelper.Info("", " MerkleRoot: ", $"{block.MerkleRoot}");
ConsoleHelper.Info("", " PrevHash: ", $"{block.PrevHash}");
ConsoleHelper.Info("", " NextConsensus: ", $"{block.NextConsensus}");
ConsoleHelper.Info("", " PrimaryIndex: ", $"{block.PrimaryIndex}");
ConsoleHelper.Info("", " Version: ", $"{block.Version}");
ConsoleHelper.Info("", " Size: ", $"{block.Size} Byte(s)");
ConsoleHelper.Info();

ConsoleHelper.Info("", "-------------", "Witness", "-------------");
ConsoleHelper.Info();
ConsoleHelper.Info("", " Invocation Script: ", $"{Convert.ToBase64String(block.Witness.InvocationScript.Span)}");
ConsoleHelper.Info("", " Verification Script: ", $"{Convert.ToBase64String(block.Witness.VerificationScript.Span)}");
ConsoleHelper.Info("", " ScriptHash: ", $"{block.Witness.ScriptHash}");
ConsoleHelper.Info("", " Size: ", $"{block.Witness.Size} Byte(s)");
ConsoleHelper.Info();

ConsoleHelper.Info("", "-------------", "Transactions", "-------------");
ConsoleHelper.Info();

if (block.Transactions.Length == 0)
{
ConsoleHelper.Info("", " No Transaction(s)");
}
else
{
foreach (var tx in block.Transactions)
ConsoleHelper.Info($" {tx.Hash}");
}
ConsoleHelper.Info();
ConsoleHelper.Info("", "--------------------------------------");
}

[ConsoleCommand("show tx", Category = "Blockchain Commands")]
public void OnShowTransactionCommand(UInt256 hash)
{
var tx = NativeContract.Ledger.GetTransactionState(_neoSystem.StoreView, hash);

if (tx is null)
{
ConsoleHelper.Error($"Transaction {hash} doesn't exist.");
return;
}

var block = NativeContract.Ledger.GetHeader(_neoSystem.StoreView, tx.BlockIndex);

DateTime transactionDatetime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
transactionDatetime = transactionDatetime.AddMilliseconds(block.Timestamp).ToLocalTime();

ConsoleHelper.Info("", "-------------", "Transaction", "-------------");
ConsoleHelper.Info();
ConsoleHelper.Info("", " Timestamp: ", $"{transactionDatetime}");
ConsoleHelper.Info("", " Hash: ", $"{tx.Transaction.Hash}");
ConsoleHelper.Info("", " Nonce: ", $"{tx.Transaction.Nonce}");
ConsoleHelper.Info("", " Sender: ", $"{tx.Transaction.Sender}");
ConsoleHelper.Info("", " ValidUntilBlock: ", $"{tx.Transaction.ValidUntilBlock}");
ConsoleHelper.Info("", " FeePerByte: ", $"{tx.Transaction.FeePerByte}");
ConsoleHelper.Info("", " NetworkFee: ", $"{tx.Transaction.NetworkFee}");
ConsoleHelper.Info("", " SystemFee: ", $"{tx.Transaction.SystemFee}");
ConsoleHelper.Info("", " Script: ", $"{Convert.ToBase64String(tx.Transaction.Script.Span)}");
ConsoleHelper.Info("", " Version: ", $"{tx.Transaction.Version}");
ConsoleHelper.Info("", " BlockIndex: ", $"{block.Index}");
ConsoleHelper.Info("", " BlockHash: ", $"{block.Hash}");
ConsoleHelper.Info("", " Size: ", $"{tx.Transaction.Size} Byte(s)");
ConsoleHelper.Info();

ConsoleHelper.Info("", "-------------", "Signers", "-------------");
ConsoleHelper.Info();

foreach (var signer in tx.Transaction.Signers)
{
if (signer.Rules.Length == 0)
ConsoleHelper.Info("", " Rules: ", "[]");
else
ConsoleHelper.Info("", " Rules: ", $"[{string.Join(", ", signer.Rules.Select(s => $"\"{s.ToJson()}\""))}]");
ConsoleHelper.Info("", " Account: ", $"{signer.Account}");
ConsoleHelper.Info("", " Scopes: ", $"{signer.Scopes}");
if (signer.AllowedContracts.Length == 0)
ConsoleHelper.Info("", " AllowedContracts: ", "[]");
else
ConsoleHelper.Info("", " AllowedContracts: ", $"[{string.Join(", ", signer.AllowedContracts.Select(s => s.ToString()))}]");
if (signer.AllowedGroups.Length == 0)
ConsoleHelper.Info("", " AllowedGroups: ", "[]");
else
ConsoleHelper.Info("", " AllowedGroups: ", $"[{string.Join(", ", signer.AllowedGroups.Select(s => s.ToString()))}]");
ConsoleHelper.Info("", " Size: ", $"{signer.Size} Byte(s)");
ConsoleHelper.Info();
}

ConsoleHelper.Info("", "-------------", "Witnesses", "-------------");
ConsoleHelper.Info();
foreach (var witness in tx.Transaction.Witnesses)
{
ConsoleHelper.Info("", " InvocationScript: ", $"{Convert.ToBase64String(witness.InvocationScript.Span)}");
ConsoleHelper.Info("", " VerificationScript: ", $"{Convert.ToBase64String(witness.VerificationScript.Span)}");
ConsoleHelper.Info("", " ScriptHash: ", $"{witness.ScriptHash}");
ConsoleHelper.Info("", " Size: ", $"{witness.Size} Byte(s)");
ConsoleHelper.Info();
}

ConsoleHelper.Info("", "-------------", "Attributes", "-------------");
ConsoleHelper.Info();
if (tx.Transaction.Attributes.Length == 0)
{
ConsoleHelper.Info("", " No Attribute(s).");
}
else
{
foreach (var attribute in tx.Transaction.Attributes)
{
ConsoleHelper.Info("", " Type: ", $"{attribute.Type}");
ConsoleHelper.Info("", " AllowMultiple: ", $"{attribute.AllowMultiple}");
ConsoleHelper.Info("", " Size: ", $"{attribute.Size} Byte(s)");
}
}
ConsoleHelper.Info();
ConsoleHelper.Info("", "--------------------------------------");
}

[ConsoleCommand("show contract", Category = "Blockchain Commands")]
public void OnShowContractCommand(string nameOrHash)
{
ContractState contract = null;

if (UInt160.TryParse(nameOrHash, out var scriptHash))
contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, scriptHash);
else
{
var nativeContract = NativeContract.Contracts.SingleOrDefault(s => s.Name.Equals(nameOrHash, StringComparison.InvariantCultureIgnoreCase));

if (nativeContract != null)
contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, nativeContract.Hash);
}

if (contract is null)
{
ConsoleHelper.Error($"Contract {nameOrHash} doesn't exist.");
return;
}

ConsoleHelper.Info("", "-------------", "Contract", "-------------");
ConsoleHelper.Info();
ConsoleHelper.Info("", " Name: ", $"{contract.Manifest.Name}");
ConsoleHelper.Info("", " Hash: ", $"{contract.Hash}");
ConsoleHelper.Info("", " Id: ", $"{contract.Id}");
ConsoleHelper.Info("", " UpdateCounter: ", $"{contract.UpdateCounter}");
ConsoleHelper.Info("", " SupportedStandards: ", $"{string.Join(" ", contract.Manifest.SupportedStandards)}");
ConsoleHelper.Info("", " Checksum: ", $"{contract.Nef.CheckSum}");
ConsoleHelper.Info("", " Compiler: ", $"{contract.Nef.Compiler}");
ConsoleHelper.Info("", " SourceCode: ", $"{contract.Nef.Source}");
ConsoleHelper.Info("", " Trusts: ", $"[{string.Join(", ", contract.Manifest.Trusts.Select(s => s.ToJson()?.GetString()))}]");
if (contract.Manifest.Extra != null)
{
foreach (var extra in contract.Manifest.Extra.Properties)
{
ConsoleHelper.Info("", $" {extra.Key,18}: ", $"{extra.Value?.GetString()}");
}
}
ConsoleHelper.Info();

ConsoleHelper.Info("", "-------------", "Groups", "-------------");
ConsoleHelper.Info();
if (contract.Manifest.Groups.Length == 0)
{
ConsoleHelper.Info("", " No Group(s).");
}
else
{
foreach (var group in contract.Manifest.Groups)
{
ConsoleHelper.Info("", " PubKey: ", $"{group.PubKey}");
ConsoleHelper.Info("", " Signature: ", $"{Convert.ToBase64String(group.Signature)}");
}
}
ConsoleHelper.Info();

ConsoleHelper.Info("", "-------------", "Permissions", "-------------");
ConsoleHelper.Info();
foreach (var permission in contract.Manifest.Permissions)
{
ConsoleHelper.Info("", " Contract: ", $"{permission.Contract.ToJson()?.GetString()}");
if (permission.Methods.IsWildcard)
ConsoleHelper.Info("", " Methods: ", "*");
else
ConsoleHelper.Info("", " Methods: ", $"{string.Join(", ", permission.Methods)}");
ConsoleHelper.Info();
}

ConsoleHelper.Info("", "-------------", "Methods", "-------------");
ConsoleHelper.Info();
foreach (var method in contract.Manifest.Abi.Methods)
{
ConsoleHelper.Info("", " Name: ", $"{method.Name}");
ConsoleHelper.Info("", " Safe: ", $"{method.Safe}");
ConsoleHelper.Info("", " Offset: ", $"{method.Offset}");
ConsoleHelper.Info("", " Parameters: ", $"[{string.Join(", ", method.Parameters.Select(s => s.Type.ToString()))}]");
ConsoleHelper.Info("", " ReturnType: ", $"{method.ReturnType}");
ConsoleHelper.Info();
}

ConsoleHelper.Info("", "-------------", "Script", "-------------");
ConsoleHelper.Info();
ConsoleHelper.Info($" {Convert.ToBase64String(contract.Nef.Script.Span)}");
ConsoleHelper.Info();
ConsoleHelper.Info("", "--------------------------------");
}
}
}