diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3729ff0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f2c2c72..3d34909 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,22 +1,19 @@ name: publish on: - pull_request: - branches: - - main - types: [closed] + push: + # Sequence of patterns matched against refs/tags + tags: + - '*' jobs: release: name: Create draft release - if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') runs-on: ubuntu-latest steps: - name: Get tag id: get_tag - env: - HEAD_REF: ${{ github.event.pull_request.head.ref }} - run: echo ::set-output name=tag::${HEAD_REF#release\/} + run: echo ::set-output name=tag::$(echo $GITHUB_REF | cut -d / -f 3) - name: Create draft release id: create_release uses: actions/create-release@v1 @@ -44,7 +41,6 @@ jobs: publish-linux: name: Publish Linux needs: [release] - if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') runs-on: ubuntu-latest steps: @@ -103,7 +99,6 @@ jobs: publish-win: name: Publish Windows needs: [release] - if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') runs-on: ubuntu-latest steps: @@ -165,7 +160,6 @@ jobs: publish-mac: name: Publish macOS needs: [release] - if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') runs-on: macos-latest steps: diff --git a/README.md b/README.md index fe69f73..673d73f 100644 --- a/README.md +++ b/README.md @@ -513,3 +513,19 @@ Add-Migration [MigrationName] ## Design Tippy's page design is based on [mazipan/bulma-admin-dashboard-template](https://github.com/mazipan/bulma-admin-dashboard-template). + +## Q&A + +### I'm using Tippy in WSL and I can see the Tippy UI via localhost:5000, but the height is always 0 + +This is probably because you have proxy enabled. Try launching Tippy with the following command + +``` +unset HTTPS_PROXY HTTP_PROXY http_proxy https_proxy +path/to/Tippy +``` + +### Where can I find the CKB node data started with Tippy + +- Linux: `~/.config/Tippy` +- Win: `~/ApplicationData/Tippy` diff --git a/Tippy.sln b/Tippy.sln index 186b4e1..7594ba5 100644 --- a/Tippy.sln +++ b/Tippy.sln @@ -37,6 +37,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ckb.Molecule", "src\Ckb.Mol EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ckb.Molecule.Tests", "tests\Ckb.Molecule.Tests\Ckb.Molecule.Tests.csproj", "{3BD402C3-D2DC-4DA3-A3A2-AA880427FCF2}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tippy.Shared", "src\Tippy.Shared\Tippy.Shared.csproj", "{8620ED2F-1A7D-47FD-B7AA-D76BC2E0E37A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -91,6 +93,10 @@ Global {3BD402C3-D2DC-4DA3-A3A2-AA880427FCF2}.Debug|Any CPU.Build.0 = Debug|Any CPU {3BD402C3-D2DC-4DA3-A3A2-AA880427FCF2}.Release|Any CPU.ActiveCfg = Release|Any CPU {3BD402C3-D2DC-4DA3-A3A2-AA880427FCF2}.Release|Any CPU.Build.0 = Release|Any CPU + {8620ED2F-1A7D-47FD-B7AA-D76BC2E0E37A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8620ED2F-1A7D-47FD-B7AA-D76BC2E0E37A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8620ED2F-1A7D-47FD-B7AA-D76BC2E0E37A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8620ED2F-1A7D-47FD-B7AA-D76BC2E0E37A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..717ab40 --- /dev/null +++ b/dockerfile @@ -0,0 +1,31 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. +FROM nervos/ckb-docker-builder:bionic-rust-1.51.0 as ckb-docker-builder +WORKDIR /app +FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base +WORKDIR /app +EXPOSE 80 + +FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build +WORKDIR /src +COPY ["src/Tippy/Tippy.csproj", "src/Tippy/"] +COPY ["src/Ckb.Molecule/Ckb.Molecule.csproj", "src/Ckb.Molecule/"] +COPY ["src/Ckb.Cryptography/Ckb.Cryptography.csproj", "src/Ckb.Cryptography/"] +COPY ["src/Ckb.Types/Ckb.Types.csproj", "src/Ckb.Types/"] +COPY ["src/Tippy.Shared/Tippy.Shared.csproj", "src/Tippy.Shared/"] +COPY ["src/Tippy.Ctrl/Tippy.Ctrl.csproj", "src/Tippy.Ctrl/"] +COPY ["src/Tippy.Core/Tippy.Core.csproj", "src/Tippy.Core/"] +COPY ["src/Ckb.Rpc/Ckb.Rpc.csproj", "src/Ckb.Rpc/"] +COPY ["src/Tippy.Util/Tippy.Util.csproj", "src/Tippy.Util/"] +COPY ["src/Ckb.Address/Ckb.Address.csproj", "src/Ckb.Address/"] +RUN dotnet restore "src/Tippy/Tippy.csproj" +COPY . . +WORKDIR "/src/src/Tippy" +RUN dotnet build "Tippy.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "Tippy.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Tippy.dll"] diff --git a/src/Ckb.Address/Ckb.Address.csproj b/src/Ckb.Address/Ckb.Address.csproj index 9a16068..5d25669 100644 --- a/src/Ckb.Address/Ckb.Address.csproj +++ b/src/Ckb.Address/Ckb.Address.csproj @@ -1,7 +1,8 @@ - netstandard2.0 + net5.0 + enable embedded diff --git a/src/Ckb.Cryptography/Ckb.Cryptography.csproj b/src/Ckb.Cryptography/Ckb.Cryptography.csproj index b850020..b9523c0 100644 --- a/src/Ckb.Cryptography/Ckb.Cryptography.csproj +++ b/src/Ckb.Cryptography/Ckb.Cryptography.csproj @@ -1,10 +1,16 @@ - netstandard2.0 + net5.0 + enable embedded + + + Auto + + diff --git a/src/Ckb.Cryptography/Ckb.Cryptography.xml b/src/Ckb.Cryptography/Ckb.Cryptography.xml new file mode 100644 index 0000000..f2bd6bc --- /dev/null +++ b/src/Ckb.Cryptography/Ckb.Cryptography.xml @@ -0,0 +1,8 @@ + + + + Ckb.Cryptography + + + + diff --git a/src/Ckb.Cryptography/Secp256k1.cs b/src/Ckb.Cryptography/Secp256k1.cs index fbde7c2..0c37aa9 100644 --- a/src/Ckb.Cryptography/Secp256k1.cs +++ b/src/Ckb.Cryptography/Secp256k1.cs @@ -1,19 +1,19 @@ using System; -using Cryptography.ECDSA; - -namespace Ckb.Cryptography -{ - public static class Secp256k1 - { - public static byte[] PrivateKeyToPublicKey(byte[] privateKey, bool compressed) - { - return Secp256K1Manager.GetPublicKey(privateKey, compressed); - } - - public static string PrivateKeyToPublicKey(string privateKey, bool compressed) - { - var pk = HexStringToBytes(privateKey); - return BytesToHexString(PrivateKeyToPublicKey(pk, compressed)); +using Cryptography.ECDSA; + +namespace Ckb.Cryptography +{ + public static class Secp256k1 + { + public static byte[] PrivateKeyToPublicKey(byte[] privateKey, bool compressed) + { + return Secp256K1Manager.GetPublicKey(privateKey, compressed); + } + + public static string PrivateKeyToPublicKey(string privateKey, bool compressed) + { + var pk = HexStringToBytes(privateKey); + return BytesToHexString(PrivateKeyToPublicKey(pk, compressed)); } private static byte[] HexStringToBytes(string hex) @@ -31,6 +31,6 @@ private static byte[] HexStringToBytes(string hex) private static string BytesToHexString(byte[] bytes) { return "0x" + BitConverter.ToString(bytes).Replace("-", "").ToLower(); - } - } -} + } + } +} diff --git a/src/Ckb.Molecule/Ckb.Molecule.csproj b/src/Ckb.Molecule/Ckb.Molecule.csproj index fa87329..d1a1854 100644 --- a/src/Ckb.Molecule/Ckb.Molecule.csproj +++ b/src/Ckb.Molecule/Ckb.Molecule.csproj @@ -1,11 +1,19 @@ - netstandard2.0 + net5.0 + enable embedded + + + x64 + Auto + + + diff --git a/src/Ckb.Molecule/Ckb.Molecule.xml b/src/Ckb.Molecule/Ckb.Molecule.xml new file mode 100644 index 0000000..fcea402 --- /dev/null +++ b/src/Ckb.Molecule/Ckb.Molecule.xml @@ -0,0 +1,8 @@ + + + + Ckb.Molecule + + + + diff --git a/src/Ckb.Rpc/BaseClient.cs b/src/Ckb.Rpc/BaseClient.cs index c03142b..4144926 100644 --- a/src/Ckb.Rpc/BaseClient.cs +++ b/src/Ckb.Rpc/BaseClient.cs @@ -1,41 +1,40 @@ -using System; -using System.IO; -using System.Net; -using System.Text; -using Newtonsoft.Json; - -namespace Ckb.Rpc -{ - public class BaseClient - { - public BaseClient(string url) - { - Url = new Uri(url); - } - - readonly Uri Url; - - public T? Call(string method, params object[]? methodParams) - { - HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(Url); - webRequest.ContentType = "application/json"; - webRequest.Method = "POST"; - webRequest.KeepAlive = true; - - var request = new RequestObject - { - Method = method, - Params = methodParams - }; - var serialized = JsonConvert.SerializeObject( - request, +using System; +using System.IO; +using System.Net; +using System.Text; +using Newtonsoft.Json; + +namespace Ckb.Rpc +{ + public class BaseClient + { + public BaseClient(string url) + { + Url = new Uri(url); + } + + readonly Uri Url; + + public T? Call(string method, params object[]? methodParams) + { + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(Url); + webRequest.ContentType = "application/json"; + webRequest.Method = "POST"; + webRequest.KeepAlive = true; + var request = new RequestObject + { + Method = method, + Params = methodParams + }; + var serialized = JsonConvert.SerializeObject( + request, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore - }); - var bytes = Encoding.UTF8.GetBytes(serialized); - webRequest.ContentLength = bytes.Length; - + }); + var bytes = Encoding.UTF8.GetBytes(serialized); + webRequest.ContentLength = bytes.Length; + try { using Stream body = webRequest.GetRequestStream(); @@ -50,39 +49,39 @@ public BaseClient(string url) throw new Exception("Parse JSON RPC response failed."); } - return response.Result; - } - catch + return response.Result; + } + catch { return default; - } - } - } - - class RequestObject - { - [JsonProperty(PropertyName = "jsonrpc")] - public string Jsonrpc { get; } = "2.0"; - - [JsonProperty(PropertyName = "id")] - public string Id { get; set; } = "1"; - - [JsonProperty(PropertyName = "method")] - public string Method { get; set; } = ""; - - [JsonProperty(PropertyName = "params")] - public object[]? Params { get; set; } - } - - class ResponseObject - { - [JsonProperty(PropertyName = "jsonrpc")] - public string Jsonrpc { get; set; } = "2.0"; - - [JsonProperty(PropertyName = "id")] - public string Id { get; set; } = "1"; - - [JsonProperty(PropertyName = "result")] - public T? Result { get; set; } - } -} + } + } + } + + class RequestObject + { + [JsonProperty(PropertyName = "jsonrpc")] + public string Jsonrpc { get; } = "2.0"; + + [JsonProperty(PropertyName = "id")] + public string Id { get; set; } = "1"; + + [JsonProperty(PropertyName = "method")] + public string Method { get; set; } = ""; + + [JsonProperty(PropertyName = "params")] + public object[]? Params { get; set; } + } + + class ResponseObject + { + [JsonProperty(PropertyName = "jsonrpc")] + public string Jsonrpc { get; set; } = "2.0"; + + [JsonProperty(PropertyName = "id")] + public string Id { get; set; } = "1"; + + [JsonProperty(PropertyName = "result")] + public T? Result { get; set; } + } +} diff --git a/src/Ckb.Rpc/Client.cs b/src/Ckb.Rpc/Client.cs index 91deb9b..c49ce50 100644 --- a/src/Ckb.Rpc/Client.cs +++ b/src/Ckb.Rpc/Client.cs @@ -20,6 +20,18 @@ public Dictionary GetBlockchainInfo() return Call>("get_blockchain_info") ?? fallback; } + /// + /// get a live cell entity + /// + /// + /// + /// + public Types.LiveCell? GetLiveCell(string txhash,ulong index) + { + object[] methodParams = { new { index = Hex.UInt64ToHex(index), tx_hash= txhash },true }; + return Call("get_live_cell", methodParams) ; + } + public Types.Block? GetBlockByNumber(UInt64 num) { string[] methodParams = { Hex.UInt64ToHex(num) }; diff --git a/src/Ckb.Types/Ckb.Types.csproj b/src/Ckb.Types/Ckb.Types.csproj index c94a4da..be04787 100644 --- a/src/Ckb.Types/Ckb.Types.csproj +++ b/src/Ckb.Types/Ckb.Types.csproj @@ -1,7 +1,8 @@ - netstandard2.0 + net5.0 + enable embedded diff --git a/src/Ckb.Types/Types.cs b/src/Ckb.Types/Types.cs index 6e8bb7a..a338701 100644 --- a/src/Ckb.Types/Types.cs +++ b/src/Ckb.Types/Types.cs @@ -443,5 +443,30 @@ public class BlockTemplate [JsonProperty(PropertyName = "dao")] public string Dao { get; set; } + } + + + + public class LiveCell + { + [JsonProperty(PropertyName = "cell")] + public Cell cell { get; set; } = default; + [JsonProperty(PropertyName = "status")] + public string status { get; set; } + } + public class Cell + { + [JsonProperty(PropertyName = "data")] + public CellData data { get; set; } = default; + [JsonProperty(PropertyName = "output")] + public Output output { get; set; } = default; + + } + public class CellData + { + [JsonProperty(PropertyName = "content")] + public string content { get; set; } + [JsonProperty(PropertyName = "hash")] + public string hash { get; set; } } } diff --git a/src/Tippy.Core/Data/TippyDbContext.cs b/src/Tippy.Core/Data/TippyDbContext.cs index 9ac3597..fa55046 100644 --- a/src/Tippy.Core/Data/TippyDbContext.cs +++ b/src/Tippy.Core/Data/TippyDbContext.cs @@ -11,6 +11,8 @@ public TippyDbContext(DbContextOptions options) } public DbSet Projects { get; set; } = null!; + + public DbSet Contracts { get; set; } = null!; public DbSet Tokens { get; set; } = null!; public DbSet RecordedTransactions { get; set; } = null!; public DbSet DeniedTransactions { get; set; } = null!; @@ -35,6 +37,12 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .WithMany(p => p.RecordedTransactions) .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity() + .HasOne(t => t.Project) + .WithMany(p => p.Contracts) + .OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity() .HasOne(t => t.Project) .WithMany(p => p.DeniedTransactions) diff --git a/src/Tippy.Core/Environment.cs b/src/Tippy.Core/Environment.cs index 833de68..0a01d90 100644 --- a/src/Tippy.Core/Environment.cs +++ b/src/Tippy.Core/Environment.cs @@ -7,7 +7,28 @@ namespace Tippy.Core { public class Environment { - public static string GetAppDataFolder() => Path.Combine(GetSystemAppDataFolder(), "Tippy"); + public static string GetAppDataFolder() { + //var datapath = GetSystemAppDataFolder(); + //if (string.IsNullOrEmpty(datapath)) + //{ + // datapath = "\\"; + // if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + // { + // datapath = "/"; + // } + // else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + // { + // datapath = "/"; + // } + //} + + var datapath = AppContext.BaseDirectory; + var path= Path.Combine(datapath, "CKBSTATE"); + return path; + + + + } public static void CreateAppDataFolder() { diff --git a/src/Tippy.Core/Migrations/20210317005554_InitialCreate.cs b/src/Tippy.Core/Migrations/20210317005554_InitialCreate.cs index 1c4444f..cb23502 100644 --- a/src/Tippy.Core/Migrations/20210317005554_InitialCreate.cs +++ b/src/Tippy.Core/Migrations/20210317005554_InitialCreate.cs @@ -1,4 +1,4 @@ -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; namespace Tippy.Core.Migrations { @@ -14,6 +14,7 @@ protected override void Up(MigrationBuilder migrationBuilder) .Annotation("Sqlite:Autoincrement", true), Name = table.Column(type: "TEXT", nullable: false), Chain = table.Column(type: "TEXT", nullable: false), + NodeRpcPort = table.Column(type: "INTEGER", nullable: false), NodeNetworkPort = table.Column(type: "INTEGER", nullable: false), IndexerRpcPort = table.Column(type: "INTEGER", nullable: false), @@ -25,6 +26,24 @@ protected override void Up(MigrationBuilder migrationBuilder) table.PrimaryKey("PK_Projects", x => x.Id); }); + migrationBuilder.CreateTable( + name: "Contracts", + columns: table => new + { + id = table.Column(type: "INTEGER", nullable: false), + ProjectId = table.Column(type: "INTEGER", nullable: false), + filename = table.Column(type: "TEXT", nullable: true), + filepath = table.Column(type: "TEXT", nullable: false), + createtime= table.Column(type: "DATETIME", nullable: false), + }, + constraints: table => + { + table.PrimaryKey("PK_Contracts", x => x.id); + }); + + + + migrationBuilder.CreateTable( name: "Tokens", columns: table => new @@ -63,6 +82,8 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationBuilder.DropTable( name: "Projects"); + migrationBuilder.DropTable( + name: "Contracts"); } } } diff --git a/src/Tippy.Core/Migrations/20210331022625_AddExtraTomlToProjects.cs b/src/Tippy.Core/Migrations/20210331022625_AddExtraTomlToProjects.cs index 125fcb5..7313d4f 100644 --- a/src/Tippy.Core/Migrations/20210331022625_AddExtraTomlToProjects.cs +++ b/src/Tippy.Core/Migrations/20210331022625_AddExtraTomlToProjects.cs @@ -1,4 +1,4 @@ -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; namespace Tippy.Core.Migrations { @@ -12,6 +12,8 @@ protected override void Up(MigrationBuilder migrationBuilder) type: "TEXT", nullable: false, defaultValue: ""); + + } protected override void Down(MigrationBuilder migrationBuilder) @@ -19,6 +21,7 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationBuilder.DropColumn( name: "ExtraToml", table: "Projects"); + } } } diff --git a/src/Tippy.Core/Migrations/20210331022625_AddInitCapacityToProjects.Designer.cs b/src/Tippy.Core/Migrations/20210331022625_AddInitCapacityToProjects.Designer.cs new file mode 100644 index 0000000..b9ea879 --- /dev/null +++ b/src/Tippy.Core/Migrations/20210331022625_AddInitCapacityToProjects.Designer.cs @@ -0,0 +1,163 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Tippy.Core.Data; + +namespace Tippy.Core.Migrations +{ + [DbContext(typeof(TippyDbContext))] + [Migration("20210331022625_AddInitCapacityToProjects")] + partial class AddInitCapacityToProjects + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("Tippy.Core.Models.FailedTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Error") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ProjectId") + .HasColumnType("INTEGER"); + + b.Property("RawTransaction") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("FailedTransactions"); + }); + + modelBuilder.Entity("Tippy.Core.Models.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Chain") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExtraToml") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IndexerRpcPort") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("LockArg") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("NodeNetworkPort") + .HasColumnType("INTEGER"); + + b.Property("NodeRpcPort") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("Tippy.Core.Models.Token", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Decimals") + .HasColumnType("INTEGER"); + + b.Property("Hash") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ProjectId") + .HasColumnType("INTEGER"); + + b.Property("Symbol") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TypeScriptArgs") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TypeScriptCodeHash") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TypeScriptHashType") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("Tippy.Core.Models.FailedTransaction", b => + { + b.HasOne("Tippy.Core.Models.Project", "Project") + .WithMany("FailedTransactions") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("Tippy.Core.Models.Token", b => + { + b.HasOne("Tippy.Core.Models.Project", "Project") + .WithMany("Tokens") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("Tippy.Core.Models.Project", b => + { + b.Navigation("FailedTransactions"); + + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tippy.Core/Migrations/20210331022625_AddInitCapacityToProjects.cs b/src/Tippy.Core/Migrations/20210331022625_AddInitCapacityToProjects.cs new file mode 100644 index 0000000..445692a --- /dev/null +++ b/src/Tippy.Core/Migrations/20210331022625_AddInitCapacityToProjects.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tippy.Core.Migrations +{ + public partial class AddInitCapacityToProjects : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + + + migrationBuilder.AddColumn( + name: "InitCapacity", + table: "Projects", + type: "int", + nullable: true, + defaultValue: "2000000000000000000"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "InitCapacity", + table: "Projects"); + } + } +} diff --git a/src/Tippy.Core/Migrations/20210422045011_AddContracts.Designer.cs b/src/Tippy.Core/Migrations/20210422045011_AddContracts.Designer.cs new file mode 100644 index 0000000..a668233 --- /dev/null +++ b/src/Tippy.Core/Migrations/20210422045011_AddContracts.Designer.cs @@ -0,0 +1,202 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Tippy.Core.Data; + +namespace Tippy.Core.Migrations +{ + [DbContext(typeof(TippyDbContext))] + [Migration("20210422045011_AddContracts")] + partial class AddContracts + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("Tippy.Core.Models.DeniedTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DenyType") + .HasColumnType("INTEGER"); + + b.Property("ProjectId") + .HasColumnType("INTEGER"); + + b.Property("TxHash") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.HasIndex("TxHash", "DenyType") + .IsUnique(); + + b.ToTable("DeniedTransactions"); + }); + + modelBuilder.Entity("Tippy.Core.Models.FailedTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Error") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ProjectId") + .HasColumnType("INTEGER"); + + b.Property("RawTransaction") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("FailedTransactions"); + }); + + modelBuilder.Entity("Tippy.Core.Models.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Chain") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExtraToml") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IndexerRpcPort") + .HasColumnType("INTEGER"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("LockArg") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("NodeNetworkPort") + .HasColumnType("INTEGER"); + + b.Property("NodeRpcPort") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Projects"); + }); + + modelBuilder.Entity("Tippy.Core.Models.Token", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Decimals") + .HasColumnType("INTEGER"); + + b.Property("Hash") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ProjectId") + .HasColumnType("INTEGER"); + + b.Property("Symbol") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TypeScriptArgs") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TypeScriptCodeHash") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TypeScriptHashType") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("Tippy.Core.Models.DeniedTransaction", b => + { + b.HasOne("Tippy.Core.Models.Project", "Project") + .WithMany("DeniedTransactions") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("Tippy.Core.Models.FailedTransaction", b => + { + b.HasOne("Tippy.Core.Models.Project", "Project") + .WithMany("FailedTransactions") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("Tippy.Core.Models.Token", b => + { + b.HasOne("Tippy.Core.Models.Project", "Project") + .WithMany("Tokens") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("Tippy.Core.Models.Project", b => + { + b.Navigation("DeniedTransactions"); + + b.Navigation("FailedTransactions"); + + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Tippy.Core/Migrations/20210422045011_AddContracts.cs b/src/Tippy.Core/Migrations/20210422045011_AddContracts.cs new file mode 100644 index 0000000..bb4978c --- /dev/null +++ b/src/Tippy.Core/Migrations/20210422045011_AddContracts.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tippy.Core.Migrations +{ + public partial class AddContracts : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + + migrationBuilder.CreateTable( + + name: "Contracts", + columns: table => new + { + id = table.Column(type: "INTEGER", nullable: false), + chainid = table.Column(type: "INTEGER", nullable: false), + filename = table.Column(type: "TEXT", nullable: true), + filepath = table.Column(type: "TEXT", nullable: false), + createtime = table.Column(type: "DATETIME", nullable: false), + }, + constraints: table => + { + table.PrimaryKey("PK_Contracts", x => x.id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Contracts"); + } + } +} diff --git a/src/Tippy.Core/Migrations/TippyDbContextModelSnapshot.cs b/src/Tippy.Core/Migrations/TippyDbContextModelSnapshot.cs index 6dad37a..7841761 100644 --- a/src/Tippy.Core/Migrations/TippyDbContextModelSnapshot.cs +++ b/src/Tippy.Core/Migrations/TippyDbContextModelSnapshot.cs @@ -16,6 +16,31 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder .HasAnnotation("ProductVersion", "5.0.0"); + modelBuilder.Entity("Tippy.Core.Models.Contracts", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ProjectId") + .HasColumnType("INTEGER"); + + b.Property("chainid") + .HasColumnType("INTEGER"); + + b.Property("filename") + .HasColumnType("INTEGER"); + + b.Property("filepath") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("Contracts"); + }); + modelBuilder.Entity("Tippy.Core.Models.DeniedTransaction", b => { b.Property("Id") @@ -157,6 +182,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Tokens"); }); + modelBuilder.Entity("Tippy.Core.Models.Contracts", b => + { + b.HasOne("Tippy.Core.Models.Project", null) + .WithMany("contracts") + .HasForeignKey("ProjectId"); + }); + modelBuilder.Entity("Tippy.Core.Models.DeniedTransaction", b => { b.HasOne("Tippy.Core.Models.Project", "Project") @@ -192,6 +224,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Tippy.Core.Models.Project", b => { + b.Navigation("contracts"); + b.Navigation("DeniedTransactions"); b.Navigation("RecordedTransactions"); diff --git a/src/Tippy.Core/Models/Contracts.cs b/src/Tippy.Core/Models/Contracts.cs new file mode 100644 index 0000000..973f6e4 --- /dev/null +++ b/src/Tippy.Core/Models/Contracts.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tippy.Core.Models +{ + public class Contracts + { + + public int id { get; set; } + + + public int ProjectId { get; set; } + + public Project Project { get; set; } = default!; + + public string filename { get; set; } + + public string filepath { get; set; } + + public DateTime createtime { get; set; } + + + + } +} diff --git a/src/Tippy.Core/Models/Project.cs b/src/Tippy.Core/Models/Project.cs index 5a16af7..ffaf5a5 100644 --- a/src/Tippy.Core/Models/Project.cs +++ b/src/Tippy.Core/Models/Project.cs @@ -1,52 +1,80 @@ -using System; +using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; - -namespace Tippy.Core.Models -{ - public class Project - { - public enum ChainType - { - Mainnet, - Testnet, - Dev - } - - public int Id { get; set; } - - [Required] - public string Name { get; set; } = string.Empty; - - [Display(Name = "Chain Type")] - public ChainType Chain { get; set; } = ChainType.Dev; - - [Display(Name = "RPC Port")] - [Required] - [Range(6000, 65535, ErrorMessage = "{0} must be between {1} and {2}.")] - public int NodeRpcPort { get; set; } - - [Display(Name = "Network Port")] - [Required] - [Range(6000, 65535, ErrorMessage = "{0} must be between {1} and {2}.")] - public int NodeNetworkPort { get; set; } - - [Display(Name = "Indexer RPC Port")] - [Required] - [Range(6000, 65535, ErrorMessage = "{0} must be between {1} and {2}.")] - public int IndexerRpcPort { get; set; } - - [Display(Name = "Block Assembler Lock Arg")] - [Required] - public string LockArg { get; set; } = "0x"; - - [Display(Name = "Active")] - public bool IsActive { get; set; } - - public string ExtraToml { get; set; } = ""; - - public List Tokens { get; set; } = default!; - public List RecordedTransactions { get; set; } = default!; - public List DeniedTransactions { get; set; } = default!; - } -} +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using Microsoft.EntityFrameworkCore; + +namespace Tippy.Core.Models +{ + public class Project + { + + + + + public enum ChainType + { + Mainnet, + Testnet, + Dev + } + + public int Id { get; set; } + + [Required] + public string Name { get; set; } = string.Empty; + + [Display(Name = "Chain Type")] + public ChainType Chain { get; set; } = ChainType.Dev; + + [Display(Name = "RPC Port")] + [Required] + [Range(6000, 65535, ErrorMessage = "{0} must be between {1} and {2}.")] + public int NodeRpcPort { get; set; } + + [Display(Name = "Network Port")] + [Required] + [Range(6000, 65535, ErrorMessage = "{0} must be between {1} and {2}.")] + public int NodeNetworkPort { get; set; } + + + [Display(Name = "InitCapacity")] + [Required] + [Range(1, 18446744073709551615, ErrorMessage = "{0} must be between {1} and {2}.")] + public UInt64 InitCapacity { get; set; } = 2000000000000000000; + + + + + + + + + + [Display(Name = "Indexer RPC Port")] + [Required] + [Range(6000, 65535, ErrorMessage = "{0} must be between {1} and {2}.")] + public int IndexerRpcPort { get; set; } + + [Display(Name = "Block Assembler Lock Arg")] + [Required] + public string LockArg { get; set; } = "0x"; + + [Display(Name = "Active")] + public bool IsActive { get; set; } + + public string ExtraToml { get; set; } = ""; + + public List Tokens { get; set; } = default!; + public List RecordedTransactions { get; set; } = default!; + public List DeniedTransactions { get; set; } + + + + + public List Contracts { get; set; } = default!; + + + } +} diff --git a/src/Tippy.Core/Settings.cs b/src/Tippy.Core/Settings.cs index 78e8a23..cce1b2c 100644 --- a/src/Tippy.Core/Settings.cs +++ b/src/Tippy.Core/Settings.cs @@ -1,16 +1,16 @@ -using System.IO; -using System.Reflection; +using System.IO; +using System.Reflection; using System.Text.Json; -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; -namespace Tippy.Core -{ - public class Settings - { - public AppSettings AppSettings { get; set; } = default!; - public string AppUrl { get; set; } = ""; - - private static Settings? singleton; +namespace Tippy.Core +{ + public class Settings + { + public AppSettings AppSettings { get; set; } = default!; + public string AppUrl { get; set; } = ""; + + private static Settings? singleton; public static Settings GetSettings() { if (singleton == null) @@ -30,43 +30,43 @@ public static Settings GetSettings() } return singleton; - } - - public void Save() + } + + public void Save() { var options = new JsonSerializerOptions { WriteIndented = true }; - var json = JsonSerializer.Serialize(GetSettings(), options); - SaveJson(json); - } - - static void SaveJson(string json) - { - File.WriteAllText(FilePath, json); - } - - private static readonly string FilePath = Path.Combine(Environment.GetAppDataFolder(), "settings.json"); - - private static string SettingsTemplate - { - get - { - var resourceName = "Tippy.Core.Settings.json"; - using Stream? stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); + var json = JsonSerializer.Serialize(GetSettings(), options); + SaveJson(json); + } + + static void SaveJson(string json) + { + File.WriteAllText(FilePath, json); + } + + private static readonly string FilePath = Path.Combine(Environment.GetAppDataFolder(), "settings.json"); + + private static string SettingsTemplate + { + get + { + var resourceName = "Tippy.Core.Settings.json"; + using Stream? stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); if (stream != null) { using StreamReader reader = new(stream); return reader.ReadToEnd(); - } - return ""; - } - } - } - + } + return ""; + } + } + } + public class AppSettings { public bool OpenBrowserOnLaunch { get; set; } - } -} + } +} diff --git a/src/Tippy.Core/Tippy.Core.csproj b/src/Tippy.Core/Tippy.Core.csproj index 4743ff4..2999a56 100644 --- a/src/Tippy.Core/Tippy.Core.csproj +++ b/src/Tippy.Core/Tippy.Core.csproj @@ -6,6 +6,11 @@ embedded + + + + + diff --git a/src/Tippy.Ctrl/ChainSpecTemplate.txt b/src/Tippy.Ctrl/ChainSpecTemplate.txt index 4569454..77c12b2 100644 --- a/src/Tippy.Ctrl/ChainSpecTemplate.txt +++ b/src/Tippy.Ctrl/ChainSpecTemplate.txt @@ -34,6 +34,12 @@ capacity = 1_048_617_0000_0000 file = { bundled = "specs/cells/secp256k1_blake160_multisig_all" } create_type_id = true capacity = 100_000_0000_0000 +[[genesis.system_cells]] +capacity = 20_000_000_000_00000000 +lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +lock.args = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" +lock.hash_type = "type" + [genesis.system_cells_lock] code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" @@ -78,7 +84,7 @@ lock.hash_type = "type" [[genesis.issued_cells]] capacity = 5_198_735_037_00000000 lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" -lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7" +lock.args = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" lock.hash_type = "type" [params] diff --git a/src/Tippy.Ctrl/ChainSpecTemplate.txt.bak b/src/Tippy.Ctrl/ChainSpecTemplate.txt.bak new file mode 100644 index 0000000..4569454 --- /dev/null +++ b/src/Tippy.Ctrl/ChainSpecTemplate.txt.bak @@ -0,0 +1,97 @@ +name = "ckb_dev" + +[genesis] +version = 0 +parent_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +timestamp = 0 +compact_target = 0x20010000 +uncles_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +nonce = "0x0" + +[genesis.genesis_cell] +message = "[GENESIS_CELL_MESSAGE]" + +[genesis.genesis_cell.lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "data" + +# An array list paths to system cell files, which is absolute or relative to +# the directory containing this config file. +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_blake160_sighash_all" } +create_type_id = true +capacity = 100_000_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/dao" } +create_type_id = true +capacity = 16_000_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_data" } +create_type_id = false +capacity = 1_048_617_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_blake160_multisig_all" } +create_type_id = true +capacity = 100_000_0000_0000 + +[genesis.system_cells_lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "data" + +# Dep group cells +[[genesis.dep_groups]] +name = "secp256k1_blake160_sighash_all" +files = [ + { bundled = "specs/cells/secp256k1_data" }, + { bundled = "specs/cells/secp256k1_blake160_sighash_all" }, +] +[[genesis.dep_groups]] +name = "secp256k1_blake160_multisig_all" +files = [ + { bundled = "specs/cells/secp256k1_data" }, + { bundled = "specs/cells/secp256k1_blake160_multisig_all" }, +] + +# For first 11 block +[genesis.bootstrap_lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "type" + +# Burn +[[genesis.issued_cells]] +capacity = 8_400_000_000_00000000 +lock.code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +lock.args = "0x62e907b15cbf27d5425399ebf6f0fb50ebb88f18" +lock.hash_type = "data" + +# issue for random generated private key: d00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc +[[genesis.issued_cells]] +capacity = 20_000_000_000_00000000 +lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +lock.args = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" +lock.hash_type = "type" + +# issue for random generated private key: 63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d +[[genesis.issued_cells]] +capacity = 5_198_735_037_00000000 +lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7" +lock.hash_type = "type" + +[params] +initial_primary_epoch_reward = 1_917_808_21917808 +secondary_epoch_reward = 613_698_63013698 +max_block_cycles = 10_000_000_000 +cellbase_maturity = 0 +primary_epoch_reward_halving_interval = 8760 +epoch_duration_target = 14400 +genesis_epoch_length = 1000 +# For development and testing purposes only. +# Keep difficulty be permanent if the pow is Dummy. (default: false) +permanent_difficulty_in_dummy = true + +[pow] +func = "Dummy" diff --git a/src/Tippy.Ctrl/ClassDiagram1.cd b/src/Tippy.Ctrl/ClassDiagram1.cd new file mode 100644 index 0000000..9109a95 --- /dev/null +++ b/src/Tippy.Ctrl/ClassDiagram1.cd @@ -0,0 +1,39 @@ + + + + + + AAAAAAAAAABAAAAACAAAABAAAQAAAAAAAAAAAEAAAAA= + Process\BinariesInfo.cs + + + + + + AAAAAAAAAAAAgAAAAAAAAAAAAAgAAAAAAAAAAAAAAAA= + ProcessManager.cs + + + + + + + + ProcessManager.cs + + + + + EAAAAAAkACAAAECAgBAAQCEAAYBABAAAIAAAAEAAAAg= + ProcessManager.cs + + + + + + AAAAAAAAAAAAAAAEAAAAAAAQAAAAAAAAAAAAAAAAAAA= + ProcessManager.cs + + + + \ No newline at end of file diff --git a/src/Tippy.Ctrl/CreatesSpecToml/ModilfySpecToml.cs b/src/Tippy.Ctrl/CreatesSpecToml/ModilfySpecToml.cs new file mode 100644 index 0000000..f5ccf11 --- /dev/null +++ b/src/Tippy.Ctrl/CreatesSpecToml/ModilfySpecToml.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tippy.Core.Models; + +namespace Tippy.Ctrl +{ + public class ModilfySpecToml + { + /// + /// Init Capacity + /// + /// + /// + public static string InitCapacity(UInt64 initCapacity) + { + string ptr = string.Empty; + if (initCapacity > 0) + { + + NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat; + nfi.NumberGroupSeparator = "_"; + ptr = initCapacity.ToString("N", nfi); + if (ptr.Contains(".")) + { + ptr = ptr.Substring(0, ptr.IndexOf('.')); ; + } + + } + return ptr; + } + + /// + /// InitCstomesConstracts + /// + /// + /// + public static string InitCstomesConstracts(List cons) + { + + if (cons==null|| cons.Count <= 0) return string.Empty; + StringBuilder str = new StringBuilder(); + cons.ForEach(item=> + { + str.AppendLine("[[genesis.system_cells]]"); + str.AppendLine("file = { file = \"cells/"+item.filename+"\" }"); + str.AppendLine("create_type_id = true"); + str.AppendLine("capacity = 100_000_0000_0000"); + }); + return str.ToString(); + + } + } +} diff --git a/src/Tippy.Ctrl/Process/BinariesInfo.cs b/src/Tippy.Ctrl/Process/BinariesInfo.cs index 9425055..03bc019 100644 --- a/src/Tippy.Ctrl/Process/BinariesInfo.cs +++ b/src/Tippy.Ctrl/Process/BinariesInfo.cs @@ -7,24 +7,23 @@ internal class BinariesInfo { internal string Info { get; private set; } = ""; internal bool HasDebuggerDeps { get; private set; } = false; - readonly List binaries = new() { "ckb", "ckb-indexer", "ckb-debugger"/*, "ckb-cli"*/ }; - + readonly List binaries = new() { WorkPathManage.CkbForPaltform(ckbenum.ckb), WorkPathManage.CkbForPaltform(ckbenum.ckbindexer), WorkPathManage.CkbForPaltform(ckbenum.ckbdebugger)/*, "ckb-cli"*/ }; + //readonly List binaries = new() { "ckb.exe", "ckb-indexer.exe", "ckb-debugger.exe"/*, "ckb-cli"*/ }; internal void Refresh() { foreach (var binary in binaries) { - // ckb-debugger not supported on Windows yet. - if (OperatingSystem.IsWindows() && binary == "ckb-debugger") - { - continue; - } + ///ckb - debugger not supported on Windows yet. + //if (OperatingSystem.IsWindows() && binary == WorkPathManage.CkbForPaltform(ckbenum.ckbdebugger)) + //{ + // continue; + //} System.Diagnostics.Process process = new(); process.StartInfo.UseShellExecute = false; process.StartInfo.FileName = CommandProcess.BinaryFullPath(binary); process.StartInfo.Arguments = "--version"; process.StartInfo.WorkingDirectory = Core.Environment.GetAppDataFolder(); - process.StartInfo.RedirectStandardOutput = true; process.OutputDataReceived += (sender, e) => { @@ -43,6 +42,7 @@ internal void Refresh() { RefreshDebuggerDeps(); } + } void RefreshDebuggerDeps() @@ -56,13 +56,13 @@ void RefreshDebuggerDeps() process.StartInfo.UseShellExecute = false; process.StartInfo.FileName = dep; process.StartInfo.Arguments = "--version"; - process.StartInfo.WorkingDirectory = Core.Environment.GetAppDataFolder(); - process.StartInfo.RedirectStandardOutput = true; - process.OutputDataReceived += (sender, e) => - { - // Do not show gdb/ttyd + process.StartInfo.WorkingDirectory = Core.Environment.GetAppDataFolder(); + process.StartInfo.RedirectStandardOutput = true; + process.OutputDataReceived += (sender, e) => + { + // Do not show gdb/ttyd }; - process.Start(); + process.Start(); process.BeginOutputReadLine(); process.WaitForExit(); } diff --git a/src/Tippy.Ctrl/Process/CommandProcess.cs b/src/Tippy.Ctrl/Process/CommandProcess.cs index 549b78d..6dd8444 100644 --- a/src/Tippy.Ctrl/Process/CommandProcess.cs +++ b/src/Tippy.Ctrl/Process/CommandProcess.cs @@ -1,22 +1,24 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; - -namespace Tippy.Ctrl.Process -{ - delegate void LogEventHandler(object? sender, LogReceivedEventArgs e); - - abstract class CommandProcess - { - internal ProcessInfo ProcessInfo { get; private set; } - protected System.Diagnostics.Process? process; - public event LogEventHandler? LogReceived; - +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using Tippy.Core.Models; + +namespace Tippy.Ctrl.Process +{ + delegate void LogEventHandler(object? sender, LogReceivedEventArgs e); + + abstract class CommandProcess + { + internal ProcessInfo ProcessInfo { get; private set; } + protected System.Diagnostics.Process? process; + public event LogEventHandler? LogReceived; + internal CommandProcess(ProcessInfo processInfo) => ProcessInfo = processInfo; - - protected abstract void Configure(); - + + protected abstract void Configure(); + public bool IsRunning { get @@ -28,93 +30,132 @@ public bool IsRunning } return false; } - } - - public void Start() - { + } + + public void Start() + { + if (!Directory.Exists(WorkingDirectory())) - { - try - { - Directory.CreateDirectory(WorkingDirectory()); - } - catch (Exception ex) - { - Debug.Fail($"Failed to create folder {ex}"); - } - } - - Stop(); - - Configure(); - HandleOutput(); - - process?.Start(); - process?.BeginErrorReadLine(); - process?.BeginOutputReadLine(); - } - + { + Directory.CreateDirectory(WorkingDirectory()); + } + + Stop(); + + Configure(); + + HandleOutput(); + process?.Start(); + + process?.BeginErrorReadLine(); + process?.BeginOutputReadLine(); + } + public void Stop() { - if (process != null) - { - process.Kill(); - process.WaitForExit(); - process = null; - } - } - + if (process != null) + { + process.Kill(); + process.WaitForExit(); + process = null; + } + } + + /// + /// copy the constracts files into the ckb working scripts directory + /// + protected void CopyTheConstractFiles(List paths) + { + var specs_cells_path = WorkingScriptDirectory(); + if (!Directory.Exists(specs_cells_path)) + { + Directory.CreateDirectory(specs_cells_path); + try + { + foreach (var item in paths) + { + if (File.Exists(item.filepath)) + { + File.Copy(item.filepath, Path.Combine(specs_cells_path, item.filename)); + + } + } + } + catch (Exception e) + { + + } + } + } + + + + protected void HandleOutput() - { - if (process == null) - { - return; - } - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.RedirectStandardError = true; - - process.OutputDataReceived += (sender, e) => - { - LogReceived?.Invoke( - this, - new LogReceivedEventArgs() - { - ID = ProcessInfo.ID, - Log = e.Data - }); - }; - - process.ErrorDataReceived += (sender, e) => - { - LogReceived?.Invoke( - this, - new LogReceivedEventArgs() - { - ID = ProcessInfo.ID, - Log = e.Data - }); - }; - } - - internal string WorkingDirectory() => - Path.Combine(Core.Environment.GetAppDataFolder(), $"chain-{ProcessInfo.ID}"); - - internal static string BinaryFullPath(string binary) => - Path.Combine(Path.Combine(BinDepsDirectory()), binary); - - protected static string[] BinDepsDirectory() - { - var platformFolder = "win"; - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - platformFolder = "mac"; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - platformFolder = "linux"; - } - - return new[] { AppContext.BaseDirectory, "BinDeps", platformFolder }; - } - } -} + { + if (process == null) + { + return; + } + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardError = true; + + process.OutputDataReceived += (sender, e) => + { + LogReceived?.Invoke( + this, + new LogReceivedEventArgs() + { + ID = ProcessInfo.ID, + Log = e.Data + }); + }; + + process.ErrorDataReceived += (sender, e) => + { + LogReceived?.Invoke( + this, + new LogReceivedEventArgs() + { + ID = ProcessInfo.ID, + Log = e.Data + }); + }; + } + + + internal string WorkingDirectory() => WorkPathManage.WorkingDirectory(ProcessInfo.ID); + + + + /// + /// set the scripts directory + /// + /// + internal string ScriptDirectory() => WorkPathManage.BinDepsPath(); + + /// + /// set the working scripts directory + /// + /// + internal string WorkingScriptDirectory() => WorkPathManage.WorkingScriptDirectory(ProcessInfo.ID); + + + internal static string BinaryFullPath(string binary) => WorkPathManage.BinaryFullPath(binary); + + + + + internal static string[] BinDepsDirectory() + { + return WorkPathManage.BinDepsDirectory(); + } + + internal static string BinDepsPath(string childDirectory = "") + { + return WorkPathManage.BinDepsPath(childDirectory); + + } + + } +} diff --git a/src/Tippy.Ctrl/Process/Debugger/DebuggerProcess.cs b/src/Tippy.Ctrl/Process/Debugger/DebuggerProcess.cs index c4303f5..7b4922c 100644 --- a/src/Tippy.Ctrl/Process/Debugger/DebuggerProcess.cs +++ b/src/Tippy.Ctrl/Process/Debugger/DebuggerProcess.cs @@ -1,45 +1,45 @@ -using System; -using System.IO; - -namespace Tippy.Ctrl.Process.Debugger -{ - internal class DebuggerProcess : CommandProcess - { - private readonly string ScriptHash; - private readonly string ScriptGroupType; - private readonly string TxFilePath; - private readonly string IoType; - private readonly int IoIndex; - private readonly string? BinaryPath; - - public DebuggerProcess(ProcessInfo info, string scriptGroupType, string scriptHash, string txFilePath, string ioType, int ioIndex, string? binaryPath = null) : base(info) - { - ScriptHash = scriptHash; - ScriptGroupType = scriptGroupType; - TxFilePath = txFilePath; - IoType = ioType; - IoIndex = ioIndex; - BinaryPath = binaryPath; - } - - protected override void Configure() - { - string? workingDirectory = Path.GetDirectoryName(TxFilePath); - if (workingDirectory == null) - { - throw new Exception("No file path found!"); - } - string debuggerBinaryPath = BinaryFullPath("ckb-debugger"); - string arguments = $"--port 7682 {debuggerBinaryPath} -l 0.0.0.0:2000 -g {ScriptGroupType} -h {ScriptHash} -t {TxFilePath} -e {IoType} -i {IoIndex}"; +using System; +using System.IO; + +namespace Tippy.Ctrl.Process.Debugger +{ + internal class DebuggerProcess : CommandProcess + { + private readonly string ScriptHash; + private readonly string ScriptGroupType; + private readonly string TxFilePath; + private readonly string IoType; + private readonly int IoIndex; + private readonly string? BinaryPath; + + public DebuggerProcess(ProcessInfo info, string scriptGroupType, string scriptHash, string txFilePath, string ioType, int ioIndex, string? binaryPath = null) : base(info) + { + ScriptHash = scriptHash; + ScriptGroupType = scriptGroupType; + TxFilePath = txFilePath; + IoType = ioType; + IoIndex = ioIndex; + BinaryPath = binaryPath; + } + + protected override void Configure() + { + string? workingDirectory = Path.GetDirectoryName(TxFilePath); + if (workingDirectory == null) + { + throw new Exception("No file path found!"); + } + string debuggerBinaryPath = BinaryFullPath(WorkPathManage.CkbForPaltform(ckbenum.ckbdebugger)); + string arguments = $"--port 7682 {debuggerBinaryPath} -l 0.0.0.0:2000 -g {ScriptGroupType} -h {ScriptHash} -t {TxFilePath} -e {IoType} -i {IoIndex}"; if (BinaryPath != null) { arguments += $" -r {BinaryPath}"; - } - process = new System.Diagnostics.Process(); - process.StartInfo.UseShellExecute = false; - process.StartInfo.FileName = "ttyd"; - process.StartInfo.WorkingDirectory = workingDirectory; - process.StartInfo.Arguments = arguments; - } - } -} + } + process = new System.Diagnostics.Process(); + process.StartInfo.UseShellExecute = false; + process.StartInfo.FileName = "ttyd"; + process.StartInfo.WorkingDirectory = workingDirectory; + process.StartInfo.Arguments = arguments; + } + } +} diff --git a/src/Tippy.Ctrl/Process/Debugger/GdbProcess.cs b/src/Tippy.Ctrl/Process/Debugger/GdbProcess.cs index 0ad5452..0902202 100644 --- a/src/Tippy.Ctrl/Process/Debugger/GdbProcess.cs +++ b/src/Tippy.Ctrl/Process/Debugger/GdbProcess.cs @@ -1,54 +1,54 @@ -using System; -using System.IO; +using System; +using System.IO; using System.Reflection; -namespace Tippy.Ctrl.Process.Debugger -{ - internal class GdbProcess : CommandProcess - { - private readonly string DebugFilePath; - - public GdbProcess(ProcessInfo info, string debugFilePath) : base(info) - { - DebugFilePath = debugFilePath; - } - - protected override void Configure() - { - string? workingDirectory = Path.GetDirectoryName(DebugFilePath); - if (workingDirectory == null) - { - throw new Exception("No file path found!"); - } - CopyGdbInit(); - string arguments = $"gdb {DebugFilePath} -iex \"source {GdbInitFilePath}\" -ex \"target remote 127.0.0.1:2000\""; - process = new System.Diagnostics.Process(); - process.StartInfo.UseShellExecute = false; - process.StartInfo.FileName = "ttyd"; - process.StartInfo.WorkingDirectory = workingDirectory; +namespace Tippy.Ctrl.Process.Debugger +{ + internal class GdbProcess : CommandProcess + { + private readonly string DebugFilePath; + + public GdbProcess(ProcessInfo info, string debugFilePath) : base(info) + { + DebugFilePath = debugFilePath; + } + + protected override void Configure() + { + string? workingDirectory = Path.GetDirectoryName(DebugFilePath); + if (workingDirectory == null) + { + throw new Exception("No file path found!"); + } + CopyGdbInit(); + string arguments = $"gdb {DebugFilePath} -iex \"source {GdbInitFilePath}\" -ex \"target remote 127.0.0.1:2000\""; + process = new System.Diagnostics.Process(); + process.StartInfo.UseShellExecute = false; + process.StartInfo.FileName = "ttyd"; + process.StartInfo.WorkingDirectory = workingDirectory; process.StartInfo.Arguments = arguments; } static string GdbInitFilePath => Path.Combine(Core.Environment.GetAppDataFolder(), ".gdbinit"); - private static void CopyGdbInit() - { - if (File.Exists(GdbInitFilePath)) - { - return; - } - - StreamWriter writer = new(GdbInitFilePath); - writer.Write(GdbInitFile()); - writer.Close(); + private static void CopyGdbInit() + { + if (File.Exists(GdbInitFilePath)) + { + return; + } + + StreamWriter writer = new(GdbInitFilePath); + writer.Write(GdbInitFile()); + writer.Close(); } - private static string GdbInitFile() - { - var resourceName = "Tippy.Ctrl.GdbDashboard.txt"; - using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)!; - using StreamReader reader = new(stream); - return reader.ReadToEnd(); - } - } -} + private static string GdbInitFile() + { + var resourceName = "Tippy.Ctrl.GdbDashboard.txt"; + using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)!; + using StreamReader reader = new(stream); + return reader.ReadToEnd(); + } + } +} diff --git a/src/Tippy.Ctrl/Process/Debugger/ProcessManager.cs b/src/Tippy.Ctrl/Process/Debugger/ProcessManager.cs index ff8cb1c..07998d8 100644 --- a/src/Tippy.Ctrl/Process/Debugger/ProcessManager.cs +++ b/src/Tippy.Ctrl/Process/Debugger/ProcessManager.cs @@ -1,39 +1,39 @@ using Tippy.Core.Models; -namespace Tippy.Ctrl.Process.Debugger -{ - public class ProcessManager - { - private static GdbProcess? GdbProcessInstance; - private static DebuggerProcess? DebuggerProcessInstance; - - public static void Start(Project project, string scriptGroupType, string scriptHash, string txFilePath, string debugFilePath, string ioType, int ioIndex, string? binaryForDebugger) - { - Stop(); - ProcessInfo processInfo = ProcessInfo.FromProject(project); - GdbProcessInstance = new GdbProcess(processInfo, debugFilePath); - DebuggerProcessInstance = new DebuggerProcess(processInfo, scriptGroupType, scriptHash, txFilePath, ioType, ioIndex, binaryForDebugger); - DebuggerProcessInstance.Start(); - GdbProcessInstance.Start(); - } - - public static void Stop() - { - GdbProcessInstance?.Stop(); - DebuggerProcessInstance?.Stop(); - } - - public static void SetEnv() - { - // BUGBUG: .Net won't find commands on M1 Mac which has homebrew location at `/opt/homebrew/bin`, - // or on Linux which at `~/.linuxbrew/bin`. - var path = System.Environment.GetEnvironmentVariable("PATH") ?? ""; - if (!string.IsNullOrEmpty(path)) - { - path += ":"; - } - path += "/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:~/.linuxbrew/bin"; - System.Environment.SetEnvironmentVariable("PATH", path); - } - } -} +namespace Tippy.Ctrl.Process.Debugger +{ + public class ProcessManager + { + private static GdbProcess? GdbProcessInstance; + private static DebuggerProcess? DebuggerProcessInstance; + + public static void Start(Project project, string scriptGroupType, string scriptHash, string txFilePath, string debugFilePath, string ioType, int ioIndex, string? binaryForDebugger) + { + Stop(); + ProcessInfo processInfo = ProcessInfo.FromProject(project); + GdbProcessInstance = new GdbProcess(processInfo, debugFilePath); + DebuggerProcessInstance = new DebuggerProcess(processInfo, scriptGroupType, scriptHash, txFilePath, ioType, ioIndex, binaryForDebugger); + DebuggerProcessInstance.Start(); + GdbProcessInstance.Start(); + } + + public static void Stop() + { + GdbProcessInstance?.Stop(); + DebuggerProcessInstance?.Stop(); + } + + public static void SetEnv() + { + // BUGBUG: .Net won't find commands on M1 Mac which has homebrew location at `/opt/homebrew/bin`, + // or on Linux which at `~/.linuxbrew/bin`. + var path = System.Environment.GetEnvironmentVariable("PATH") ?? ""; + if (!string.IsNullOrEmpty(path)) + { + path += ":"; + } + path += "/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:~/.linuxbrew/bin"; + System.Environment.SetEnvironmentVariable("PATH", path); + } + } +} diff --git a/src/Tippy.Ctrl/Process/IndexerProcess.cs b/src/Tippy.Ctrl/Process/IndexerProcess.cs index c7fcc23..c42295e 100644 --- a/src/Tippy.Ctrl/Process/IndexerProcess.cs +++ b/src/Tippy.Ctrl/Process/IndexerProcess.cs @@ -10,7 +10,8 @@ protected override void Configure() { process = new System.Diagnostics.Process(); process.StartInfo.UseShellExecute = false; - process.StartInfo.FileName = BinaryFullPath("ckb-indexer"); + //process.StartInfo.FileName = BinaryFullPath("ckb-indexer.exe"); + process.StartInfo.FileName = BinaryFullPath(WorkPathManage.CkbForPaltform(ckbenum.ckbindexer)); process.StartInfo.WorkingDirectory = WorkingDirectory(); process.StartInfo.Arguments = $"-s indexer-data -c http://127.0.0.1:{ProcessInfo.NodeRpcPort} -l 127.0.0.1:{ProcessInfo.IndexerRpcPort}"; } diff --git a/src/Tippy.Ctrl/Process/InitConstractFileModel.cs b/src/Tippy.Ctrl/Process/InitConstractFileModel.cs new file mode 100644 index 0000000..b109074 --- /dev/null +++ b/src/Tippy.Ctrl/Process/InitConstractFileModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tippy.Ctrl.Process +{ + internal class InitConstractFileModel + { + public string filename { get; set; } + + public string filepath { get; set; } + + public string capacity { get; set; } = "100_000_0000_0000"; + } +} diff --git a/src/Tippy.Ctrl/Process/MinerProcess.cs b/src/Tippy.Ctrl/Process/MinerProcess.cs index 0ad817e..f3ef4ab 100644 --- a/src/Tippy.Ctrl/Process/MinerProcess.cs +++ b/src/Tippy.Ctrl/Process/MinerProcess.cs @@ -1,46 +1,47 @@ -using System; +using System; using System.IO; using System.Linq; -namespace Tippy.Ctrl.Process -{ - internal class MinerProcess : CommandProcess - { - internal MinerProcess(ProcessInfo info) : base(info) { } - - protected override void Configure() - { - UpdateConfiguration(); - - process = new System.Diagnostics.Process(); - process.StartInfo.UseShellExecute = false; - process.StartInfo.FileName = BinaryFullPath("ckb"); - process.StartInfo.WorkingDirectory = WorkingDirectory(); - process.StartInfo.Arguments = "miner"; - } - - void UpdateConfiguration() - { - try - { - var tomlContent = File.ReadLines(TomlFile); - var updatedContent = tomlContent.Select((line) => - { - if (line.StartsWith("rpc_url = ")) - { - return $"rpc_url = \"http://127.0.0.1:{ProcessInfo.NodeRpcPort}\""; - } - else - { - return line; - } - }); - File.WriteAllLines(TomlFile, updatedContent.ToArray()); - } - catch - { } - } - - string TomlFile => Path.Combine(WorkingDirectory(), "ckb-miner.toml"); - } -} +namespace Tippy.Ctrl.Process +{ + internal class MinerProcess : CommandProcess + { + internal MinerProcess(ProcessInfo info) : base(info) { } + + protected override void Configure() + { + UpdateConfiguration(); + + process = new System.Diagnostics.Process(); + process.StartInfo.UseShellExecute = false; + + process.StartInfo.FileName = BinaryFullPath(WorkPathManage.CkbForPaltform(ckbenum.ckb)); + process.StartInfo.WorkingDirectory = WorkingDirectory(); + process.StartInfo.Arguments = "miner"; + } + + void UpdateConfiguration() + { + try + { + var tomlContent = File.ReadLines(TomlFile); + var updatedContent = tomlContent.Select((line) => + { + if (line.StartsWith("rpc_url = ")) + { + return $"rpc_url = \"http://127.0.0.1:{ProcessInfo.NodeRpcPort}\""; + } + else + { + return line; + } + }); + File.WriteAllLines(TomlFile, updatedContent.ToArray()); + } + catch + { } + } + + string TomlFile => Path.Combine(WorkingDirectory(), "ckb-miner.toml"); + } +} diff --git a/src/Tippy.Ctrl/Process/NodeProcess.cs b/src/Tippy.Ctrl/Process/NodeProcess.cs index 0309bff..d3d1e8b 100644 --- a/src/Tippy.Ctrl/Process/NodeProcess.cs +++ b/src/Tippy.Ctrl/Process/NodeProcess.cs @@ -1,62 +1,83 @@ -using System; -using System.IO; +using System; +using System.Globalization; +using System.IO; using System.Linq; -using System.Reflection; -using System.Text; +using System.Reflection; +using System.Text; + +namespace Tippy.Ctrl.Process +{ + internal class NodeProcess : CommandProcess + { + internal NodeProcess(ProcessInfo info) : base(info) { } + + protected override void Configure() + { + + InitalizeCkbIfNecessary(); + UpdateConfiguration(); + + process = new System.Diagnostics.Process(); + process.StartInfo.UseShellExecute = false; + + process.StartInfo.FileName = BinaryFullPath(WorkPathManage.CkbForPaltform(ckbenum.ckb)); + process.StartInfo.WorkingDirectory = WorkingDirectory(); + process.StartInfo.Arguments = "run"; + } + + void InitalizeCkbIfNecessary() + { + if (File.Exists(TomlFile)) + { + return; + } + + using System.Diagnostics.Process process = new(); + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardInput = true; + + process.StartInfo.FileName = BinaryFullPath(WorkPathManage.CkbForPaltform(ckbenum.ckb)); + process.StartInfo.WorkingDirectory = WorkingDirectory(); + process.StartInfo.Arguments = BuildArguments(); + + + + process.Start(); + + StreamWriter writer = process.StandardInput; + writer.Write(ChainSpec()); + writer.Close(); + + process.WaitForExit(); + CopyTheConstractFiles(ProcessInfo.Contracts); + } + + public void Reset() + { + try + { + var filepath = Path.Combine(WorkingDirectory(), "indexer-data"); + if (File.Exists(filepath)) + Directory.Delete(filepath, true); + + } + catch (Exception e) + { + Console.WriteLine($"Failed to reset project data, {e.Message}"); + } + try + { + var filepath = Path.Combine(WorkingDirectory(), "data"); + if (File.Exists(filepath)) + Directory.Delete(Path.Combine(WorkingDirectory(), "data"), true); + } + catch (Exception e) + { + Console.WriteLine($"Failed to reset project data, {e.Message}"); + } + + } -namespace Tippy.Ctrl.Process -{ - internal class NodeProcess : CommandProcess - { - internal NodeProcess(ProcessInfo info) : base(info) { } - - protected override void Configure() - { - InitalizeCkbIfNecessary(); - UpdateConfiguration(); - - process = new System.Diagnostics.Process(); - process.StartInfo.UseShellExecute = false; - process.StartInfo.FileName = BinaryFullPath("ckb"); - process.StartInfo.WorkingDirectory = WorkingDirectory(); - process.StartInfo.Arguments = "run"; - } - - void InitalizeCkbIfNecessary() - { - if (File.Exists(TomlFile)) - { - return; - } - - using System.Diagnostics.Process process = new(); - process.StartInfo.UseShellExecute = false; - process.StartInfo.RedirectStandardInput = true; - process.StartInfo.FileName = BinaryFullPath("ckb"); - process.StartInfo.WorkingDirectory = WorkingDirectory(); - process.StartInfo.Arguments = BuildArguments(); - process.Start(); - - StreamWriter writer = process.StandardInput; - writer.Write(ChainSpec()); - writer.Close(); - - process.WaitForExit(); - } - - public void Reset() - { - try - { - Directory.Delete(Path.Combine(WorkingDirectory(), "indexer-data"), true); - Directory.Delete(Path.Combine(WorkingDirectory(), "data"), true); - } - catch (Exception e) - { - Console.WriteLine($"Failed to reset project data, {e.Message}"); - } - } - void UpdateConfiguration() { try @@ -89,41 +110,67 @@ void UpdateConfiguration() } catch { } - } - + } + string TomlFile => Path.Combine(WorkingDirectory(), "ckb.toml"); - - string BuildArguments() - { + static string chainspectemplatefile => Path.Combine(new[] { AppContext.BaseDirectory, "BinDeps", "ChainSpecTemplate.txt" }); + + string BuildArguments() + { return ProcessInfo.Chain switch { Core.Models.Project.ChainType.Testnet => $"init --chain testnet --ba-arg {ProcessInfo.LockArg}", Core.Models.Project.ChainType.Mainnet => $"init --chain mainnet --ba-arg {ProcessInfo.LockArg}", _ => $"init --chain dev --ba-arg {ProcessInfo.LockArg} --import-spec -", }; - } - - string ChainSpec() - { - var spec = DevChainSpecTemplate; - spec = spec.Replace("[GENESIS_CELL_MESSAGE]", "ckb_dev_" + ProcessInfo.ID); - if (!String.IsNullOrEmpty(ProcessInfo.ExtraToml)) - { - spec += "\n" + ProcessInfo.ExtraToml + "\n"; - } - var bytes = Encoding.UTF8.GetBytes(spec); - return Convert.ToBase64String(bytes); - } - - private static string DevChainSpecTemplate - { - get - { - var resourceName = "Tippy.Ctrl.ChainSpecTemplate.txt"; - using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)!; - using StreamReader reader = new StreamReader(stream); - return reader.ReadToEnd(); - } - } - } -} + } + + string ChainSpec() + { + var spec = DevChainSpecTemplate; + spec = spec.Replace("[GENESIS_CELL_MESSAGE]", "ckb_dev_" + ProcessInfo.ID); + spec = spec.Replace("0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7", ProcessInfo.LockArg); + var initcapacity = ModilfySpecToml.InitCapacity(ProcessInfo.InitCapacity); + var cstomesConstracts = ModilfySpecToml.InitCstomesConstracts(ProcessInfo.Contracts); + if (!string.IsNullOrEmpty(initcapacity)) + { + spec = spec.Replace("{{Capacity}}", initcapacity); + } + if (!string.IsNullOrEmpty(initcapacity)) + { + spec = spec.Replace("{{Customes_System_Cells}}", cstomesConstracts); + } + else + { + spec = spec.Replace("{{Customes_System_Cells}}", string.Empty); + } + if (!String.IsNullOrEmpty(ProcessInfo.ExtraToml)) + { + spec += "\n" + ProcessInfo.ExtraToml + "\n"; + } + var bytes = Encoding.UTF8.GetBytes(spec); + return Convert.ToBase64String(bytes); + } + + private static string DevChainSpecTemplate + { + get + { + //var resourceName = "Tippy.Ctrl.ChainSpecTemplate.txt"; + //using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)!; + //using StreamReader reader = new StreamReader(stream); + //return reader.ReadToEnd(); + + if (File.Exists(chainspectemplatefile)) + { + return System.IO.File.ReadAllText(chainspectemplatefile); + } + else + { + return ""; + } + + } + } + } +} diff --git a/src/Tippy.Ctrl/ProcessGroup.cs b/src/Tippy.Ctrl/ProcessGroup.cs index 9d18dc4..a48ab2a 100644 --- a/src/Tippy.Ctrl/ProcessGroup.cs +++ b/src/Tippy.Ctrl/ProcessGroup.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; +using System.IO; using System.Linq; using System.Timers; using Ckb.Rpc; @@ -33,10 +33,10 @@ internal ProcessGroup(ProcessInfo processInfo) internal bool IsAdvancedMinerRunning => advancedMiningTimer != null; internal bool CanStartMining => IsRunning && !(IsMinerRunning || IsAdvancedMinerRunning); - internal string LogFolder() - { - Process.NodeProcess p = new(ProcessInfo); - return Path.Combine(p.WorkingDirectory(), "data", "logs"); + internal string LogFolder() + { + Process.NodeProcess p = new(ProcessInfo); + return Path.Combine(p.WorkingDirectory(), "data", "logs"); } internal void Start() diff --git a/src/Tippy.Ctrl/ProcessInfo.cs b/src/Tippy.Ctrl/ProcessInfo.cs index 52beeab..095b804 100644 --- a/src/Tippy.Ctrl/ProcessInfo.cs +++ b/src/Tippy.Ctrl/ProcessInfo.cs @@ -1,12 +1,17 @@ +using System; +using System.Collections.Generic; using Tippy.Core.Models; namespace Tippy.Ctrl { - public record ProcessInfo(int ID, Project.ChainType Chain, int NodeRpcPort, int NodeNetworkPort, - int IndexerRpcPort, string LockArg, string ExtraToml) + public record ProcessInfo(int ID, Project.ChainType Chain, int NodeRpcPort, int NodeNetworkPort, + int IndexerRpcPort, string LockArg, string ExtraToml, List Contracts, UInt64 InitCapacity) { + public static ProcessInfo FromProject(Project project) => - new(project.Id, project.Chain, project.NodeRpcPort, project.NodeNetworkPort, - project.IndexerRpcPort, project.LockArg, project.ExtraToml); + + new(project.Id, + project.Chain, project.NodeRpcPort, project.NodeNetworkPort, + project.IndexerRpcPort, project.LockArg, project.ExtraToml,project.Contracts,project.InitCapacity); } } diff --git a/src/Tippy.Ctrl/ProcessManager.cs b/src/Tippy.Ctrl/ProcessManager.cs index ed409e6..5080a25 100644 --- a/src/Tippy.Ctrl/ProcessManager.cs +++ b/src/Tippy.Ctrl/ProcessManager.cs @@ -5,7 +5,7 @@ namespace Tippy.Ctrl { - public class LogReceivedEventArgs : EventArgs + public class LogReceivedEventArgs : EventArgs { public int ID { get; init; } public string? Log { get; init; } @@ -15,27 +15,27 @@ public class LogReceivedEventArgs : EventArgs public class ProcessManager { - public static event NodeLogEventHandler? NodeLogReceived; - + public static event NodeLogEventHandler? NodeLogReceived; + /// /// CKB related binaries version info - /// - public static string Info { get; private set; } = ""; - - public static bool DebuggerDepsInstalled { get; private set; } = false; - + /// + public static string Info { get; private set; } = ""; + + public static bool DebuggerDepsInstalled { get; private set; } = false; + public enum MinerMode { Default, SingleBlock, Sophisticated, - } - - static readonly List processGroups = new(); - - static ProcessGroup? GroupFor(Project project) => - processGroups.Find(g => g.ProcessInfo == ProcessInfo.FromProject(project)); - + } + + static readonly List processGroups = new(); + + static ProcessGroup? GroupFor(Project project) => + processGroups.Find(g => g.ProcessInfo.ID == ProcessInfo.FromProject(project).ID); + public static bool IsRunning(Project project) => project != null && GroupFor(project) != null; public static bool IsMinerRunning(Project project) { @@ -62,8 +62,8 @@ public static bool CanStartMining(Project project) return false; } - public static string GetLogFolder(Project project) - { + public static string GetLogFolder(Project project) + { ProcessGroup group = new(ProcessInfo.FromProject(project)); return group.LogFolder(); } @@ -120,7 +120,7 @@ public static void Stop(Project project) public static void Restart(Project project) { Stop(project); - Start(project); + Start(project); } // Note: if mode is not Default, project should have DeniedTransactions loaded before calling this. @@ -153,15 +153,15 @@ public static void StopMiner(Project project) group?.StopMiner(); } - public static void ResetData(Project project) - { - Stop(project); - ProcessGroup group = new(ProcessInfo.FromProject(project)); - group.ResetData(); + public static void ResetData(Project project) + { + Stop(project); + ProcessGroup group = new(ProcessInfo.FromProject(project)); + group.ResetData(); } static void OnLogReceived(object? sender, LogReceivedEventArgs e) - { + { Console.WriteLine(e.Log); if (sender is ProcessGroup group) { diff --git a/src/Tippy.Ctrl/WorkPathManage.cs b/src/Tippy.Ctrl/WorkPathManage.cs new file mode 100644 index 0000000..e75ee14 --- /dev/null +++ b/src/Tippy.Ctrl/WorkPathManage.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Tippy.Ctrl +{ + + public enum ckbenum + { + ckb, + ckbindexer, + ckbdebugger + + } + /// + /// work directory manange + /// + public class WorkPathManage + { + internal static string WorkingDirectory(int id) => + Path.Combine(Core.Environment.GetAppDataFolder(), $"chain-{id}"); + + + + /// + /// set the scripts directory + /// + /// + public static string ScriptDirectory() => BinDepsPath("scripts"); + + /// + /// set the working scripts directory + /// + /// + public static string WorkingScriptDirectory(int id) => Path.Combine(new string[] { WorkingDirectory(id), "specs", "cells" }); + + + internal static string BinaryFullPath(string binary) => + Path.Combine(Path.Combine(BinDepsDirectory()), binary); + + + + + internal static string[] BinDepsDirectory() + { + var platformFolder = "win"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + platformFolder = "mac"; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + platformFolder = "linux"; + } + + return new[] { AppContext.BaseDirectory, "BinDeps", platformFolder }; + } + + public static string CkbForPaltform(ckbenum ckb) + { + //"ckb", "ckb-indexer", "ckb-debugger" + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return ckb switch + { + ckbenum.ckb=>"ckb", + ckbenum.ckbdebugger=> "ckb-debugger", + ckbenum.ckbindexer=> "ckb-indexer", + _=> "ckb" + }; + + + } + else + { + return ckb switch + { + ckbenum.ckb => "ckb.exe", + ckbenum.ckbdebugger => "ckb-debugger.exe", + ckbenum.ckbindexer => "ckb-indexer.exe", + _ => "ckb.exe" + }; + } + } + + + + + + internal static string BinDepsPath(string childDirectory = "") + { + if (!string.IsNullOrEmpty(childDirectory)) + { + return Path.Combine(new[] { AppContext.BaseDirectory, "BinDeps", childDirectory }); + } + else + { + return Path.Combine(new[] { AppContext.BaseDirectory, "BinDeps" }); + } + + } + + /// + /// get the the list of constract files. + /// + public static List GetListOfConstractFiles() + { + + var specs_cells_path = WorkPathManage.ScriptDirectory(); + List list = new List(); + if (Directory.Exists(specs_cells_path)) + { + + + try + { + DirectoryInfo dir = new DirectoryInfo(ScriptDirectory()); + FileSystemInfo[] fileinfo = dir.GetFileSystemInfos(); + foreach (FileSystemInfo i in fileinfo) + { + if (!(i is DirectoryInfo)) + { + list.Add(i); + + } + continue; + + } + + } + catch (Exception e) + { + + } + + } + return list; + } + + } +} diff --git a/src/Tippy.Shared/MyConstracts/Domain_ConstractFile.cs b/src/Tippy.Shared/MyConstracts/Domain_ConstractFile.cs new file mode 100644 index 0000000..ccb0dc5 --- /dev/null +++ b/src/Tippy.Shared/MyConstracts/Domain_ConstractFile.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tippy.Ctrl; + +namespace Tippy.Shared.MyConstracts +{ + + public class Domain_ConstractFile + { + /// + /// filename + /// + + public string filename { get; set; } + + /// + /// filecreate time + /// + public DateTime filecreatetime { get; set; } + + /// + /// file modify time + /// + + public DateTime modifytime { get; set; } + + /// + /// file path + /// + public string filepath { get; set; } + + /// + /// that is seleced for into ckb constract + /// + + public bool selectforintockb { get; set; } = false; + + + + /// + /// domain: return List + /// + /// + public List GetConstractFiles() + { + List list = new List(); + WorkPathManage.GetListOfConstractFiles().ForEach(item => + { + + list.Add(new Domain_ConstractFile() + { + filename = item.Name, + filepath = item.FullName, + filecreatetime = item.CreationTime, + modifytime = item.LastWriteTime, + }); + }); + return list; + } + } + +} + + + diff --git a/src/Tippy.Shared/Tippy.Shared.csproj b/src/Tippy.Shared/Tippy.Shared.csproj new file mode 100644 index 0000000..caa4f04 --- /dev/null +++ b/src/Tippy.Shared/Tippy.Shared.csproj @@ -0,0 +1,11 @@ + + + + net5.0 + + + + + + + diff --git a/src/Tippy/Api/TippyRpc.cs b/src/Tippy/Api/TippyRpc.cs index 1792c94..e3d872d 100644 --- a/src/Tippy/Api/TippyRpc.cs +++ b/src/Tippy/Api/TippyRpc.cs @@ -1,15 +1,15 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; +using System.Linq; using System.Net; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; -using System.Threading.Tasks; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Tippy.Core.Data; +using Microsoft.EntityFrameworkCore; +using Tippy.Core.Data; using Tippy.Core.Models; using Tippy.Ctrl; using Tippy.Filters; @@ -153,7 +153,8 @@ async Task CreateChain() NodeNetworkPort = calculatingFromUsed ? networkPorts.Max() + 3 : 8115, IndexerRpcPort = calculatingFromUsed ? indexerPorts.Max() + 3 : 8116, LockArg = param?.AssemblerLockArg ?? "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7", - ExtraToml = String.Join("\n\n", toml) + ExtraToml = String.Join("\n\n", toml), + }; projects.ForEach(p => p.IsActive = false); project.IsActive = true; @@ -311,7 +312,7 @@ object StopMiner() } // Mine N blocks at the default 1sec interval. - object MineBlocks() + object MineBlocks() { if (project == null) { @@ -346,7 +347,7 @@ object MineBlocks() } // Revert N blocks. - object RevertBlocks() + object RevertBlocks() { if (project == null) { @@ -513,11 +514,11 @@ class GenesisIssuedCell public LockScript Lock { get; set; } = default!; /* - [[genesis.issued_cells]] - capacity = 5_198_735_037_00000000 - lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" - lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7" - lock.hash_type = "type" + [[genesis.issued_cells]] + capacity = 5_198_735_037_00000000 + lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" + lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7" + lock.hash_type = "type" */ internal string ToTomlString() { @@ -615,16 +616,16 @@ internal static async void RecordIfNecessary(TippyDbContext dbContext, RequestOb { raw = request.Params[0]; } - var tx = new RecordedTransaction - { - ProjectId = project.Id, - TxHash = txHash?.Result?.ToString() ?? "", - RawTransaction = JsonSerializer.Serialize(raw), - Error = error?.Error?.Message ?? "", - CreatedAt = DateTime.Now - }; - - dbContext.RecordedTransactions.Add(tx); + var tx = new RecordedTransaction + { + ProjectId = project.Id, + TxHash = txHash?.Result?.ToString() ?? "", + RawTransaction = JsonSerializer.Serialize(raw), + Error = error?.Error?.Message ?? "", + CreatedAt = DateTime.Now + }; + + dbContext.RecordedTransactions.Add(tx); await dbContext.SaveChangesAsync(); } } diff --git a/src/Tippy/ApiData/TransactionResult.cs b/src/Tippy/ApiData/TransactionResult.cs index a9b20a0..3555d40 100644 --- a/src/Tippy/ApiData/TransactionResult.cs +++ b/src/Tippy/ApiData/TransactionResult.cs @@ -186,6 +186,10 @@ public class DisplayOutput // $"{txHash}:{index(int)}" [JsonPropertyName("id")] public string? Id { get; set; } = default!; + // $"{index(int)}" + [JsonPropertyName("realId")] + public int RealId { get; set; } = default!; + [JsonPropertyName("sudt_info")] public SudtInfo? SudtInfo = null; diff --git a/src/Tippy/BinDeps/ChainSpecTemplate.txt b/src/Tippy/BinDeps/ChainSpecTemplate.txt new file mode 100644 index 0000000..5a6df9d --- /dev/null +++ b/src/Tippy/BinDeps/ChainSpecTemplate.txt @@ -0,0 +1,107 @@ +name = "ckb_dev" + +[genesis] +version = 0 +parent_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +timestamp = 0 +compact_target = 0x20010000 +uncles_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +nonce = "0x0" + +[genesis.genesis_cell] +message = "[GENESIS_CELL_MESSAGE]" + +[genesis.genesis_cell.lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "data" + +# An array list paths to system cell files, which is absolute or relative to +# the directory containing this config file. +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_blake160_sighash_all" } +create_type_id = true +capacity = 100_000_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/dao" } +create_type_id = true +capacity = 16_000_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_data" } +create_type_id = false +capacity = 1_048_617_0000_0000 +[[genesis.system_cells]] +file = { bundled = "specs/cells/secp256k1_blake160_multisig_all" } +create_type_id = true +capacity = 100_000_0000_0000 +{{Customes_System_Cells}} + + + + +[genesis.system_cells_lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "data" + +# Dep group cells +[[genesis.dep_groups]] +name = "secp256k1_blake160_sighash_all" +files = [ + { bundled = "specs/cells/secp256k1_data" }, + { bundled = "specs/cells/secp256k1_blake160_sighash_all" }, +] +[[genesis.dep_groups]] +name = "secp256k1_blake160_multisig_all" +files = [ + { bundled = "specs/cells/secp256k1_data" }, + { bundled = "specs/cells/secp256k1_blake160_multisig_all" }, +] + +# For first 11 block +[genesis.bootstrap_lock] +code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +args = "0x" +hash_type = "type" + +# Burn +[[genesis.issued_cells]] +capacity = 8_400_000_000_00000000 +lock.code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +lock.args = "0x62e907b15cbf27d5425399ebf6f0fb50ebb88f18" +lock.hash_type = "data" + +# issue for random generated private key: d00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc +#[[genesis.issued_cells]] +#capacity = 20_000_000_000_00000000 +#lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +#lock.args = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" +#lock.hash_type = "type" + +# issue for random generated private key: 63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d +[[genesis.issued_cells]] +capacity = 5_198_735_037_00000000 +lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7" +lock.hash_type = "type" + +[params] +initial_primary_epoch_reward = 1_917_808_21917808 +secondary_epoch_reward = 613_698_63013698 +max_block_cycles = 10_000_000_000 +cellbase_maturity = 0 +primary_epoch_reward_halving_interval = 8760 +epoch_duration_target = 14400 +genesis_epoch_length = 1000 +# For development and testing purposes only. +# Keep difficulty be permanent if the pow is Dummy. (default: false) +permanent_difficulty_in_dummy = true + +[pow] + +func = "Dummy" +[[genesis.issued_cells]] +capacity = {{Capacity}} +lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +lock.args = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" +lock.hash_type = "type" diff --git a/src/Tippy/BinDeps/linux/ckb b/src/Tippy/BinDeps/linux/ckb new file mode 100644 index 0000000..9da8997 Binary files /dev/null and b/src/Tippy/BinDeps/linux/ckb differ diff --git a/src/Tippy/BinDeps/linux/ckb-debugger b/src/Tippy/BinDeps/linux/ckb-debugger new file mode 100644 index 0000000..31bbc66 Binary files /dev/null and b/src/Tippy/BinDeps/linux/ckb-debugger differ diff --git a/src/Tippy/BinDeps/linux/ckb-indexer b/src/Tippy/BinDeps/linux/ckb-indexer new file mode 100644 index 0000000..62aa824 Binary files /dev/null and b/src/Tippy/BinDeps/linux/ckb-indexer differ diff --git a/src/Tippy/BinDeps/scripts.zip b/src/Tippy/BinDeps/scripts.zip new file mode 100644 index 0000000..eba8012 Binary files /dev/null and b/src/Tippy/BinDeps/scripts.zip differ diff --git a/src/Tippy/BinDeps/win/ckb-debugger.exe b/src/Tippy/BinDeps/win/ckb-debugger.exe new file mode 100644 index 0000000..0c7cf47 Binary files /dev/null and b/src/Tippy/BinDeps/win/ckb-debugger.exe differ diff --git a/src/Tippy/BinDeps/win/ckb-indexer.exe b/src/Tippy/BinDeps/win/ckb-indexer.exe new file mode 100644 index 0000000..77ad90f Binary files /dev/null and b/src/Tippy/BinDeps/win/ckb-indexer.exe differ diff --git a/src/Tippy/BinDeps/win/ckb.exe b/src/Tippy/BinDeps/win/ckb.exe new file mode 100644 index 0000000..7d688ef Binary files /dev/null and b/src/Tippy/BinDeps/win/ckb.exe differ diff --git a/src/Tippy/BinDeps/win/ckb/ckb-debugger.exe b/src/Tippy/BinDeps/win/ckb/ckb-debugger.exe new file mode 100644 index 0000000..0c7cf47 Binary files /dev/null and b/src/Tippy/BinDeps/win/ckb/ckb-debugger.exe differ diff --git a/src/Tippy/BinDeps/win/ckb/ckb-indexer.exe b/src/Tippy/BinDeps/win/ckb/ckb-indexer.exe new file mode 100644 index 0000000..77ad90f Binary files /dev/null and b/src/Tippy/BinDeps/win/ckb/ckb-indexer.exe differ diff --git a/src/Tippy/BinDeps/win/ckb/ckb.exe b/src/Tippy/BinDeps/win/ckb/ckb.exe new file mode 100644 index 0000000..7d688ef Binary files /dev/null and b/src/Tippy/BinDeps/win/ckb/ckb.exe differ diff --git a/src/Tippy/Dockerfile b/src/Tippy/Dockerfile new file mode 100644 index 0000000..765428b --- /dev/null +++ b/src/Tippy/Dockerfile @@ -0,0 +1,30 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base +WORKDIR /app +EXPOSE 80 + +FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build +WORKDIR /src +COPY ["src/Tippy/Tippy.csproj", "src/Tippy/"] +COPY ["src/Ckb.Molecule/Ckb.Molecule.csproj", "src/Ckb.Molecule/"] +COPY ["src/Ckb.Cryptography/Ckb.Cryptography.csproj", "src/Ckb.Cryptography/"] +COPY ["src/Ckb.Types/Ckb.Types.csproj", "src/Ckb.Types/"] +COPY ["src/Tippy.Shared/Tippy.Shared.csproj", "src/Tippy.Shared/"] +COPY ["src/Tippy.Ctrl/Tippy.Ctrl.csproj", "src/Tippy.Ctrl/"] +COPY ["src/Tippy.Core/Tippy.Core.csproj", "src/Tippy.Core/"] +COPY ["src/Ckb.Rpc/Ckb.Rpc.csproj", "src/Ckb.Rpc/"] +COPY ["src/Tippy.Util/Tippy.Util.csproj", "src/Tippy.Util/"] +COPY ["src/Ckb.Address/Ckb.Address.csproj", "src/Ckb.Address/"] +RUN dotnet restore "src/Tippy/Tippy.csproj" +COPY . . +WORKDIR "/src/src/Tippy" +RUN dotnet build "Tippy.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "Tippy.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Tippy.dll"] diff --git a/src/Tippy/Helpers/NumberHelper.cs b/src/Tippy/Helpers/NumberHelper.cs index c07e159..09d0c3b 100644 --- a/src/Tippy/Helpers/NumberHelper.cs +++ b/src/Tippy/Helpers/NumberHelper.cs @@ -1,12 +1,12 @@ -using System; -using Tippy.Util; - -namespace Tippy.Helpers -{ - public static class NumberHelper - { - public static string CkbAmount(string capacity) => Amount(capacity); - +using System; +using Tippy.Util; + +namespace Tippy.Helpers +{ + public static class NumberHelper + { + public static string CkbAmount(string capacity) => Amount(capacity); + public static string Amount(string amount, int decimalDigits = 8) { var result = String.Format( @@ -21,11 +21,11 @@ public static string Amount(string amount, int decimalDigits = 8) result = result[0..^1]; } return result; - } - - public static string HexToNumber(string hex) - { - return Hex.HexToUInt64(hex).ToString(); - } - } -} + } + + public static string HexToNumber(string hex) + { + return Hex.HexToUInt64(hex).ToString(); + } + } +} diff --git a/src/Tippy/Helpers/TransactionHelper.cs b/src/Tippy/Helpers/TransactionHelper.cs index dfadfaf..31d4c52 100644 --- a/src/Tippy/Helpers/TransactionHelper.cs +++ b/src/Tippy/Helpers/TransactionHelper.cs @@ -53,8 +53,35 @@ public static (DisplayInput[] DisplayInputs, DisplayOutput[] DisplayOutputs) Gen GeneratedTxHash = txHash, } }; - var dOutputs = Array.Empty(); - return (dInputs, dOutputs); + + // var dOutputs = Array.Empty(); + var dOutputs = outputs.Select((output, i) => + { + return new DisplayOutput + { + Id = $"{txHash}:{i}", + Capacity = Hex.HexToUInt64(output.Capacity).ToString(), + AddressHash = Ckb.Address.Address.GenerateAddress(output.Lock, prefix), + TargetBlockNumber = blockNumber.ToString(), + RealId = i, + //PrimaryReward = Hex.HexToUInt64(minerReward.Primary).ToString(), + //SecondaryReward = Hex.HexToUInt64(minerReward.Secondary).ToString(), + //CommitReward = Hex.HexToUInt64(minerReward.Committed).ToString(), + //ProposalReward = Hex.HexToUInt64(minerReward.Proposal).ToString(), + + // TODO: update Status & ConsumedTxHash + Status = "live", + ConsumedTxHash = "", + }; + }).ToArray(); + var doutlist = dOutputs.ToList(); + //if the 0 block,specal deal unuse data + if (blockNumber == 0&& doutlist.Count>9) + { + doutlist.RemoveRange(0, 5); //by the dev setting cell + doutlist.RemoveRange(doutlist.Count() - 4, 4); //by the dev setting cell + } + return (dInputs, doutlist.ToArray()); } UInt64 targetBlockNumber = blockNumber + 1 - (UInt64)TxProposalWindow; var displayInputs = new DisplayInput[] @@ -87,7 +114,7 @@ public static (DisplayInput[] DisplayInputs, DisplayOutput[] DisplayOutputs) Gen Capacity = Hex.HexToUInt64(output.Capacity).ToString(), AddressHash = Ckb.Address.Address.GenerateAddress(output.Lock, prefix), TargetBlockNumber = targetBlockNumber.ToString(), - + RealId = i, PrimaryReward = Hex.HexToUInt64(minerReward.Primary).ToString(), SecondaryReward = Hex.HexToUInt64(minerReward.Secondary).ToString(), CommitReward = Hex.HexToUInt64(minerReward.Committed).ToString(), diff --git a/src/Tippy/Pages/Debugger/Details.cshtml b/src/Tippy/Pages/Debugger/Details.cshtml index 27d4125..3e35c07 100644 --- a/src/Tippy/Pages/Debugger/Details.cshtml +++ b/src/Tippy/Pages/Debugger/Details.cshtml @@ -1,4 +1,4 @@ -@page +@page @model Tippy.Pages.Debugger.DetailsModel @{ ViewData["Title"] = "Debugger"; } @@ -35,13 +35,17 @@
- +
- +
@section Scripts { @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } + } diff --git a/src/Tippy/Pages/Debugger/Details.cshtml.cs b/src/Tippy/Pages/Debugger/Details.cshtml.cs index f3952c1..3e583f6 100644 --- a/src/Tippy/Pages/Debugger/Details.cshtml.cs +++ b/src/Tippy/Pages/Debugger/Details.cshtml.cs @@ -1,26 +1,26 @@ -using System; -using Ckb.Types.MockTransactionTypes; -using Ckb.Types; -using System.Linq; -using Ckb.Rpc; -using Ckb.Molecule.Type; -using Ckb.Cryptography; -using System.IO; -using System.Collections.Generic; -using Microsoft.AspNetCore.Mvc; - -using DebuggerProcessManager = Tippy.Ctrl.Process.Debugger.ProcessManager; -using TypesConvert = Ckb.Types.Convert; +using System; +using Ckb.Types.MockTransactionTypes; +using Ckb.Types; +using System.Linq; +using Ckb.Rpc; +using Ckb.Molecule.Type; +using Ckb.Cryptography; +using System.IO; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; + +using DebuggerProcessManager = Tippy.Ctrl.Process.Debugger.ProcessManager; +using TypesConvert = Ckb.Types.Convert; using Microsoft.EntityFrameworkCore; using Tippy.Core.Models; using System.Threading.Tasks; -namespace Tippy.Pages.Debugger -{ - public class DetailsModel : PageModelBase - { - public DetailsModel(Tippy.Core.Data.TippyDbContext context) : base(context) - { +namespace Tippy.Pages.Debugger +{ + public class DetailsModel : PageModelBase + { + public DetailsModel(Tippy.Core.Data.TippyDbContext context) : base(context) + { } [BindProperty] @@ -37,36 +37,36 @@ public IActionResult OnPost(string? txHash, string? ioType, int? ioIndex, int? s : $"/Debugger/Details?txId={txId}&ioType={ioType}&ioIndex={ioIndex}&scriptType={scriptType}&filePath={FilePath}"; return Redirect(url); - } - + } + public IActionResult OnPostClose() { DebuggerProcessManager.Stop(); return Redirect("/Home"); - } - - public async Task OnGet(string? txHash, string? ioType, int? ioIndex, int? scriptType, string? filePath, int? txId = null) - { + } + + public async Task OnGet(string? txHash, string? ioType, int? ioIndex, int? scriptType, string? filePath, int? txId = null) + { if (ioType != "input" && ioType != "output") { throw new Exception("ioType must be `input` or `output`!"); - } - if (ioIndex == null) - { - throw new Exception("ioIndex cannot be null!"); - } - if (scriptType == null) - { - throw new Exception("scriptType cannot be null!"); - } + } + if (ioIndex == null) + { + throw new Exception("ioIndex cannot be null!"); + } + if (scriptType == null) + { + throw new Exception("scriptType cannot be null!"); + } if (txId == null && (txHash == null || txHash == "")) { throw new Exception("txId and txHash cannot be all null!"); - } - - Client client = Rpc(); - - Transaction transaction; + } + + Client client = Rpc(); + + Transaction transaction; if (txId != null) { RecordedTransaction? failedTransaction = await DbContext.RecordedTransactions.FirstOrDefaultAsync(t => t.Id == txId); @@ -91,9 +91,9 @@ public async Task OnGet(string? txHash, string? ioType, int? ioIn throw new Exception($"Transaction not found: {txHash}"); } transaction = txWithStatus.Transaction; - } - - Output output = transaction.Outputs[(int)ioIndex]; + } + + Output output = transaction.Outputs[(int)ioIndex]; if (ioType == "input") { Input input = transaction.Inputs[(int)ioIndex]; @@ -103,245 +103,245 @@ public async Task OnGet(string? txHash, string? ioType, int? ioIn if (scriptType == 1 && output.Type == null) { throw new Exception($"Type script not found in {{tx_hash: {txHash}, index: {ioIndex}, ioType: {ioType}}}"); - } - - Script script = scriptType == 0 ? output.Lock : output.Type; - string scriptHash = ComputeScriptHash(script); - MockTransaction mockTx = DumpTransaction(client, transaction); - mockTx.Tx.Hash = null; - - string targetContractData = GetCellDepData(mockTx, script); - - string binaryFilePath = WriteToFile(scriptHash, targetContractData); - - string? binaryForDebugger = null; - if (filePath != null) - { - binaryFilePath = filePath; - binaryForDebugger = filePath; - } - - string mockTxFilePath = WriteMockTx(scriptHash, mockTx.ToJson()); - - string scriptGroupType = scriptType == 0 ? "lock" : "type"; - try - { - DebuggerProcessManager.Start(ActiveProject!, scriptGroupType, scriptHash, mockTxFilePath, binaryFilePath, ioType, (int)ioIndex, binaryForDebugger); - } - catch (System.InvalidOperationException e) - { - TempData["ErrorMessage"] = e.Message; - } - - return Page(); - } - - private static string GetCellDepData(MockTransaction mockTx, Script script) - { + } + + Script script = scriptType == 0 ? output.Lock : output.Type; + string scriptHash = ComputeScriptHash(script); + MockTransaction mockTx = DumpTransaction(client, transaction); + mockTx.Tx.Hash = null; + + string targetContractData = GetCellDepData(mockTx, script); + + string binaryFilePath = WriteToFile(scriptHash, targetContractData); + + string? binaryForDebugger = null; + if (filePath != null) + { + binaryFilePath = filePath; + binaryForDebugger = filePath; + } + + string mockTxFilePath = WriteMockTx(scriptHash, mockTx.ToJson()); + + string scriptGroupType = scriptType == 0 ? "lock" : "type"; + try + { + DebuggerProcessManager.Start(ActiveProject!, scriptGroupType, scriptHash, mockTxFilePath, binaryFilePath, ioType, (int)ioIndex, binaryForDebugger); + } + catch (System.InvalidOperationException e) + { + TempData["ErrorMessage"] = e.Message; + } + + return Page(); + } + + private static string GetCellDepData(MockTransaction mockTx, Script script) + { if (script.HashType == "data") - { - return GetCellDepDataByDataHash(mockTx, script.CodeHash); - } - return GetCellDepDataByTypeHash(mockTx, script.CodeHash); - } - - private static string GetCellDepDataByDataHash(MockTransaction mockTx, string codeHash) - { - foreach (MockCellDep cellDep in mockTx.MockInfo.CellDeps) - { - string dataHash = ComputeDataHash(cellDep.Data); - if (codeHash == dataHash) - { - return cellDep.Data; - } - } - throw new Exception("CellDep not found!"); - } - - private static string GetCellDepDataByTypeHash(MockTransaction mockTx, string codeHash) - { - foreach (MockCellDep cellDep in mockTx.MockInfo.CellDeps) - { - if (cellDep.Output.Type != null) - { - string typeHash = ComputeScriptHash(cellDep.Output.Type); - if (codeHash == typeHash) - { - return cellDep.Data; - } - } - } - throw new Exception("CellDep not found!"); - } - - private static string ComputeScriptHash(Script script) - { - return TypesConvert.BytesToHexString(Blake2bHasher.ComputeHash(new ScriptSerializer(script).Serialize())); - } - - private static string ComputeDataHash(string data) - { - return TypesConvert.BytesToHexString(Blake2bHasher.ComputeHash(TypesConvert.HexStringToBytes(data))); - } - - private static string WriteMockTx(string name, string jsonData) - { - string tempPath = Path.GetTempPath(); - string filePath = Path.Join(tempPath, "Tippy", "DebuggerBinaries", $"{name}.json"); - - System.IO.File.WriteAllText(filePath, jsonData); - - return filePath; - } - - private static string WriteToFile(string name, string data) - { - string tempPath = Path.GetTempPath(); - string filePathWithoutName = Path.Join(tempPath, "Tippy", "DebuggerBinaries"); + { + return GetCellDepDataByDataHash(mockTx, script.CodeHash); + } + return GetCellDepDataByTypeHash(mockTx, script.CodeHash); + } + + private static string GetCellDepDataByDataHash(MockTransaction mockTx, string codeHash) + { + foreach (MockCellDep cellDep in mockTx.MockInfo.CellDeps) + { + string dataHash = ComputeDataHash(cellDep.Data); + if (codeHash == dataHash) + { + return cellDep.Data; + } + } + throw new Exception("CellDep not found!"); + } + + private static string GetCellDepDataByTypeHash(MockTransaction mockTx, string codeHash) + { + foreach (MockCellDep cellDep in mockTx.MockInfo.CellDeps) + { + if (cellDep.Output.Type != null) + { + string typeHash = ComputeScriptHash(cellDep.Output.Type); + if (codeHash == typeHash) + { + return cellDep.Data; + } + } + } + throw new Exception("CellDep not found!"); + } + + private static string ComputeScriptHash(Script script) + { + return TypesConvert.BytesToHexString(Blake2bHasher.ComputeHash(new ScriptSerializer(script).Serialize())); + } + + private static string ComputeDataHash(string data) + { + return TypesConvert.BytesToHexString(Blake2bHasher.ComputeHash(TypesConvert.HexStringToBytes(data))); + } + + private static string WriteMockTx(string name, string jsonData) + { + string tempPath = Path.GetTempPath(); + string filePath = Path.Join(tempPath, "Tippy", "DebuggerBinaries", $"{name}.json"); + + System.IO.File.WriteAllText(filePath, jsonData); + + return filePath; + } + + private static string WriteToFile(string name, string data) + { + string tempPath = Path.GetTempPath(); + string filePathWithoutName = Path.Join(tempPath, "Tippy", "DebuggerBinaries"); if (!Directory.Exists(filePathWithoutName)) - { - Directory.CreateDirectory(filePathWithoutName); - } - string filePath = Path.Join(filePathWithoutName, name); - - using var stream = new FileStream( - filePath, - FileMode.Create, - FileAccess.ReadWrite); - - var bytes = Ckb.Types.Convert.HexStringToBytes(data); - stream.Write(bytes); - - stream.Close(); - - return filePath; - } - - private static MockTransaction DumpTransaction(Client client, Transaction tx) - { - MockInput[] mockInputs = tx.Inputs.Select((input) => GetMockInput(client, input)).ToArray(); - MockCellDep[] mockCellDeps = tx.CellDeps.SelectMany((cellDep) => GetMockCellDep(client, cellDep)).ToArray(); - Header[] mockHeaders = tx.HeaderDeps.Select((headerDep) => GetMockHeader(client, headerDep)).ToArray(); - - MockTransaction mockTx = new MockTransaction - { - MockInfo = new MockInfo - { - Inputs = mockInputs, - CellDeps = mockCellDeps, - HeaderDeps = mockHeaders, - }, - Tx = tx - }; - return mockTx; - } - - private static MockInput GetMockInput(Client client, Input input) - { - TransactionWithStatus? txWithStatus = client.GetTransaction(input.PreviousOutput.TxHash); - if (txWithStatus == null) - { - throw new Exception("Cannot find input cell"); - } - int index = (int)TypesConvert.HexToUInt32(input.PreviousOutput.Index); - - MockInput mockInput = new MockInput - { - Input = input, - Output = txWithStatus.Transaction.Outputs[index], - Data = txWithStatus.Transaction.OutputsData[index], - }; - - return mockInput; - } - - private static MockCellDep[] GetMockCellDep(Client client, CellDep cellDep) + { + Directory.CreateDirectory(filePathWithoutName); + } + string filePath = Path.Join(filePathWithoutName, name); + + using var stream = new FileStream( + filePath, + FileMode.Create, + FileAccess.ReadWrite); + + var bytes = Ckb.Types.Convert.HexStringToBytes(data); + stream.Write(bytes); + + stream.Close(); + + return filePath; + } + + private static MockTransaction DumpTransaction(Client client, Transaction tx) + { + MockInput[] mockInputs = tx.Inputs.Select((input) => GetMockInput(client, input)).ToArray(); + MockCellDep[] mockCellDeps = tx.CellDeps.SelectMany((cellDep) => GetMockCellDep(client, cellDep)).ToArray(); + Header[] mockHeaders = tx.HeaderDeps.Select((headerDep) => GetMockHeader(client, headerDep)).ToArray(); + + MockTransaction mockTx = new MockTransaction + { + MockInfo = new MockInfo + { + Inputs = mockInputs, + CellDeps = mockCellDeps, + HeaderDeps = mockHeaders, + }, + Tx = tx + }; + return mockTx; + } + + private static MockInput GetMockInput(Client client, Input input) { - TransactionWithStatus? txWithStatus = client.GetTransaction(cellDep.OutPoint.TxHash); - if (txWithStatus == null) - { - throw new Exception($"Cannot find cell dep: {{ tx_hash: {cellDep.OutPoint.TxHash}, index: {cellDep.OutPoint.Index} }}!"); - } - int index = (int)TypesConvert.HexToUInt32(cellDep.OutPoint.Index); - - string data = txWithStatus.Transaction.OutputsData[index]; - Output output = txWithStatus.Transaction.Outputs[index]; - - List mockCellDeps = new(); + TransactionWithStatus? txWithStatus = client.GetTransaction(input.PreviousOutput.TxHash); + if (txWithStatus == null) + { + throw new Exception("Cannot find input cell"); + } + int index = (int)TypesConvert.HexToUInt32(input.PreviousOutput.Index); + + MockInput mockInput = new MockInput + { + Input = input, + Output = txWithStatus.Transaction.Outputs[index], + Data = txWithStatus.Transaction.OutputsData[index], + }; + + return mockInput; + } + + private static MockCellDep[] GetMockCellDep(Client client, CellDep cellDep) + { + TransactionWithStatus? txWithStatus = client.GetTransaction(cellDep.OutPoint.TxHash); + if (txWithStatus == null) + { + throw new Exception($"Cannot find cell dep: {{ tx_hash: {cellDep.OutPoint.TxHash}, index: {cellDep.OutPoint.Index} }}!"); + } + int index = (int)TypesConvert.HexToUInt32(cellDep.OutPoint.Index); + + string data = txWithStatus.Transaction.OutputsData[index]; + Output output = txWithStatus.Transaction.Outputs[index]; + + List mockCellDeps = new(); mockCellDeps.Add(new MockCellDep() { CellDep = cellDep, Output = output, Data = data, - }); - - if (cellDep.DepType == "dep_group") - { - CellDep[] cellDeps = UnpackDepGroup(data); + }); + + if (cellDep.DepType == "dep_group") + { + CellDep[] cellDeps = UnpackDepGroup(data); foreach (CellDep dep in cellDeps) { mockCellDeps.AddRange(GetMockCellDep(client, dep)); - } - } - - return mockCellDeps.ToArray(); - } - - private static CellDep[] UnpackDepGroup(string data) - { - var outPoints = DeserializeOutPointVec(data); + } + } + + return mockCellDeps.ToArray(); + } + + private static CellDep[] UnpackDepGroup(string data) + { + var outPoints = DeserializeOutPointVec(data); return outPoints.Select((outPoint) => - { - return new CellDep() - { - OutPoint = outPoint, - DepType = "code", - }; - }).ToArray(); - } - - private static Header GetMockHeader(Client client, string headerDep) - { - Header? header = client.GetHeader(headerDep); - if (header == null) - { - throw new Exception($"Cannot find header: {headerDep}"); - } - return header; - } - - private static OutPoint[] DeserializeOutPointVec(string data) - { - byte[] bytes = TypesConvert.HexStringToBytes(data); - int size = (int)BitConverter.ToUInt32(bytes.Take(4).ToArray()); - int totalSize = bytes.Skip(4).ToArray().Length; - int singleSize = totalSize / size; - - List outPoints = new(); - - for (int i = 0; i < size; i++) - { - int startAt = i * singleSize + 4; - byte[] outPointBytes = bytes.Skip(startAt).Take(singleSize).ToArray(); - OutPoint outPoint = DeserializeOutPoint(outPointBytes); - outPoints.Add(outPoint); - } - - return outPoints.ToArray(); - } - - private static OutPoint DeserializeOutPoint(byte[] bytes) - { - byte[] txHashBytes = bytes.Take(32).ToArray(); - int index = (int)BitConverter.ToUInt32(bytes.Skip(32).Take(4).ToArray()); - - OutPoint outPoint = new() - { - TxHash = TypesConvert.BytesToHexString(txHashBytes), - Index = TypesConvert.Int32ToHex(index), - }; - - return outPoint; - } - } -} + { + return new CellDep() + { + OutPoint = outPoint, + DepType = "code", + }; + }).ToArray(); + } + + private static Header GetMockHeader(Client client, string headerDep) + { + Header? header = client.GetHeader(headerDep); + if (header == null) + { + throw new Exception($"Cannot find header: {headerDep}"); + } + return header; + } + + private static OutPoint[] DeserializeOutPointVec(string data) + { + byte[] bytes = TypesConvert.HexStringToBytes(data); + int size = (int)BitConverter.ToUInt32(bytes.Take(4).ToArray()); + int totalSize = bytes.Skip(4).ToArray().Length; + int singleSize = totalSize / size; + + List outPoints = new(); + + for (int i = 0; i < size; i++) + { + int startAt = i * singleSize + 4; + byte[] outPointBytes = bytes.Skip(startAt).Take(singleSize).ToArray(); + OutPoint outPoint = DeserializeOutPoint(outPointBytes); + outPoints.Add(outPoint); + } + + return outPoints.ToArray(); + } + + private static OutPoint DeserializeOutPoint(byte[] bytes) + { + byte[] txHashBytes = bytes.Take(32).ToArray(); + int index = (int)BitConverter.ToUInt32(bytes.Skip(32).Take(4).ToArray()); + + OutPoint outPoint = new() + { + TxHash = TypesConvert.BytesToHexString(txHashBytes), + Index = TypesConvert.Int32ToHex(index), + }; + + return outPoint; + } + } +} diff --git a/src/Tippy/Pages/Home/Index.cshtml b/src/Tippy/Pages/Home/Index.cshtml index d843701..24eee26 100644 --- a/src/Tippy/Pages/Home/Index.cshtml +++ b/src/Tippy/Pages/Home/Index.cshtml @@ -1,5 +1,5 @@ @page "/" -@using Tippy.Util +@using Tippy.Util @model Tippy.Pages.Home.IndexModel @{ ViewData["Title"] = "Dashboard"; @@ -17,35 +17,35 @@ @if (Model.Projects.Count == 0) { -
-
- - - -
- -

You haven't set up any chain yet. To get started, you can...

- -
- -
+
-

or

+

You haven't set up any chain yet. To get started, you can...

-
- - - - - Create a customized chain to run - +
+ +
+ +

or

+ +
- } @if (Model.ActiveProject != null) @@ -95,56 +95,80 @@
@Model.TipBlockNumber
@if (Model.ActiveProject.Chain == Tippy.Core.Models.Project.ChainType.Dev) { -
Miner
- - @if (Model.IsMinerRunning) - { -
-
- +
Miner
+ + @if (Model.IsMinerRunning) + { + +
+ +
+ + } + else + { + var disabled = !Model.CanStartMining; +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
- +

+ Advanced mining +

+ } } else { - var disabled = !Model.CanStartMining; -
-
- -
-
- -
-
-

- Advanced mining -

+
Miner
+
Mining is disabled for @Model.ActiveProject.Chain.ToString().ToLower()
} - } - else - { -
Miner
-
Mining is disabled for @Model.ActiveProject.Chain.ToString().ToLower()
- }
@@ -243,11 +267,53 @@ } } -@section scripts { +@section Scripts{ } diff --git a/src/Tippy/Pages/Home/Index.cshtml.cs b/src/Tippy/Pages/Home/Index.cshtml.cs index 8fa2278..ef6c630 100644 --- a/src/Tippy/Pages/Home/Index.cshtml.cs +++ b/src/Tippy/Pages/Home/Index.cshtml.cs @@ -1,8 +1,10 @@ using System; +using System.Threading.Tasks; using Ckb.Address; using Ckb.Types; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Tippy.Core; +using Tippy.Core; using Tippy.Ctrl; namespace Tippy.Pages.Home @@ -23,14 +25,19 @@ public IndexModel(Tippy.Core.Data.TippyDbContext context) : base(context) public bool IsMinerRunning { get; set; } public bool CanStartMining { get; set; } + + public Task OnGetMinerMoreBlocks(int? id) + { + var referer = Request.GetTypedHeaders().Referer.ToString().ToLower(); + return Task.FromResult(RedirectToPage("./Index")); + } public void OnGet() { IsNodeRunning = ActiveProject != null && ProcessManager.IsRunning(ActiveProject); IsMinerRunning = IsNodeRunning && ProcessManager.IsMinerRunning(ActiveProject!); CanStartMining = IsNodeRunning && ProcessManager.CanStartMining(ActiveProject!); - - if (Settings.GetSettings().AppUrl.EndsWith("/")) - { + if (Settings.GetSettings().AppUrl.EndsWith("/")) + { ApiUrl = Settings.GetSettings().AppUrl + "api"; } else diff --git a/src/Tippy/Pages/Home/QuickStart.cshtml.cs b/src/Tippy/Pages/Home/QuickStart.cshtml.cs index 6a3fc6f..cb57960 100644 --- a/src/Tippy/Pages/Home/QuickStart.cshtml.cs +++ b/src/Tippy/Pages/Home/QuickStart.cshtml.cs @@ -1,7 +1,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Tippy.Core.Models; using Tippy.Ctrl; diff --git a/src/Tippy/Pages/Miners/GenerateBlock.cshtml.cs b/src/Tippy/Pages/Miners/GenerateBlock.cshtml.cs index 494ba74..b44f9ab 100644 --- a/src/Tippy/Pages/Miners/GenerateBlock.cshtml.cs +++ b/src/Tippy/Pages/Miners/GenerateBlock.cshtml.cs @@ -18,6 +18,39 @@ public GenerateBlockModel(Tippy.Core.Data.TippyDbContext context) : base(context public Project? Project { get; set; } public void OnGet() { + + } + + public async Task OnGetMinerMoreBlocks(int? id,int? count) + { + //if (id == null) + //{ + // return NotFound(); + //} + + Project = await DbContext.Projects + .Include(p => p.DeniedTransactions) + .Where(p => p.Id == id) + .FirstOrDefaultAsync(); + + if (Project != null) + { + try + { + for (int i = 0; i < count; i++) + { + ProcessManager.StartMiner(Project, ProcessManager.MinerMode.SingleBlock); + } + + } + catch (System.InvalidOperationException e) + { + TempData["ErrorMessage"] = e.Message; + } + } + + var referer = Request.GetTypedHeaders().Referer.ToString().ToLower(); + return new JsonResult("ok"); } public async Task OnPostAsync(int? id) @@ -32,11 +65,13 @@ public async Task OnPostAsync(int? id) .Where(p => p.Id == id) .FirstOrDefaultAsync(); + + if (Project != null) { try { - ProcessManager.StartMiner(Project, ProcessManager.MinerMode.SingleBlock); + ProcessManager.StartMiner(Project, ProcessManager.MinerMode.SingleBlock); } catch (System.InvalidOperationException e) { diff --git a/src/Tippy/Pages/MyConstract/Index.cshtml b/src/Tippy/Pages/MyConstract/Index.cshtml new file mode 100644 index 0000000..441c6f7 --- /dev/null +++ b/src/Tippy/Pages/MyConstract/Index.cshtml @@ -0,0 +1,111 @@ +@page +@model Tippy.Pages.MyConstract.IndexModel + +@{ ViewData["Title"] = "MyContract"; } + +
+
+

Constracts

+
+
+ +
+ +
+ +
+ + + +
+ + +
+
+
+ + + + + + + + + + + + + + + @foreach (var item in Model.constractFiles) + { + + + + + + + } + +
ConstractNameCreateTimeModifyTimeOperation
@item.filename@item.filecreatetime@item.modifytime
+
+@section Scripts{ + +} + diff --git a/src/Tippy/Pages/MyConstract/Index.cshtml.cs b/src/Tippy/Pages/MyConstract/Index.cshtml.cs new file mode 100644 index 0000000..d376367 --- /dev/null +++ b/src/Tippy/Pages/MyConstract/Index.cshtml.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Tippy.Core.Models; +using Tippy.Ctrl; +using Tippy.Shared.MyConstracts; +using Tippy.Utils; + +namespace Tippy.Pages.MyConstract +{ + public class IndexModel : PageModelBase + { + public IndexModel(Tippy.Core.Data.TippyDbContext context) : base(context) + { + } + + public Dictionary RunningFlags { get; set; } = new Dictionary(); + + public List constractFiles = new List(); + + [BindProperty] + public FileUpload FileUpload { get; set; } + + + + + + public IActionResult OnPost() + { + + using (var fileStream = new FileStream(Path.Combine(WorkPathManage.ScriptDirectory(), FileUpload.UploadPrivateSchedule.FileName), FileMode.Create)) + { + FileUpload.UploadPrivateSchedule.CopyTo(fileStream); + } + + return RedirectToPage("./Index"); + } + + /// + /// get constract file list + /// + /// + public void OnGet() + { + Domain_ConstractFile constracts = new Domain_ConstractFile(); + + constractFiles= constracts.GetConstractFiles(); + + } + /// + /// get constract file list + /// + /// + + public Task OnPostDelete(string filepath) + { + if (System.IO.File.Exists(filepath)) + { + System.IO.File.Delete(filepath); + } + return Task.FromResult< IActionResult>( RedirectToPage("./Index")); + } + + } +} diff --git a/src/Tippy/Pages/PageModelBase.cs b/src/Tippy/Pages/PageModelBase.cs index 314121f..00f55f7 100644 --- a/src/Tippy/Pages/PageModelBase.cs +++ b/src/Tippy/Pages/PageModelBase.cs @@ -2,14 +2,14 @@ using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; -using Ckb.Rpc; -using Ckb.Types; +using Ckb.Rpc; +using Ckb.Types; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.EntityFrameworkCore; using Tippy.Core.Models; -using Tippy.Ctrl; - +using Tippy.Ctrl; + namespace Tippy.Pages { /// @@ -22,6 +22,7 @@ public class PageModelBase : PageModel protected readonly Tippy.Core.Data.TippyDbContext DbContext; public IList Projects { get; set; } = new List(); + public Project? ActiveProject { get; set; } public UInt64 TipBlockNumber { get; set; } public EpochView? EpochView { get; set; } diff --git a/src/Tippy/Pages/Projects/Create.cshtml b/src/Tippy/Pages/Projects/Create.cshtml index 6dfde85..7844752 100644 --- a/src/Tippy/Pages/Projects/Create.cshtml +++ b/src/Tippy/Pages/Projects/Create.cshtml @@ -8,7 +8,40 @@
-
+
+
+
+

+ Select Contracts into chain. +

+ +
+ + +
+
@@ -17,6 +50,7 @@
+
@@ -39,6 +73,17 @@
+ + + + +
+
+ + + +
+
@@ -68,5 +113,13 @@
@section Scripts { + @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} + } diff --git a/src/Tippy/Pages/Projects/Create.cshtml.cs b/src/Tippy/Pages/Projects/Create.cshtml.cs index 39f4034..639572a 100644 --- a/src/Tippy/Pages/Projects/Create.cshtml.cs +++ b/src/Tippy/Pages/Projects/Create.cshtml.cs @@ -1,11 +1,15 @@ +using System; using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; -using Ckb.Address; +using Ckb.Address; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Tippy.Core.Models; - +using Tippy.Ctrl; +using Tippy.Shared.MyConstracts; namespace Tippy.Pages.Projects { public class CreateModel : PageModelBase @@ -14,21 +18,28 @@ public CreateModel(Tippy.Core.Data.TippyDbContext context) : base(context) { } + [BindProperty] + + [Display(Name = "Constracts")] + public List ConstractFiles{ get; set; } + public void OnGet() { + + ConstractFiles = WorkPathManage.GetListOfConstractFiles().Select(item => new Domain_ConstractFile { filename= item.Name, filepath=item.FullName}).ToList() ; var calculatingFromUsed = Projects.Count > 0; var rpcPorts = Projects.Select(p => p.NodeRpcPort); - var networkPorts = Projects.Select(p => p.NodeNetworkPort); - var indexerPorts = Projects.Select(p => p.IndexerRpcPort); - - Project = new Project - { - Name = $"CKB Chain", - Chain = Project.ChainType.Dev, - NodeRpcPort = calculatingFromUsed ? rpcPorts.Max() + 3 : 8114, - NodeNetworkPort = calculatingFromUsed ? networkPorts.Max() + 3 : 8115, - IndexerRpcPort = calculatingFromUsed ? indexerPorts.Max() + 3 : 8116, - LockArg = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" + var networkPorts = Projects.Select(p => p.NodeNetworkPort); + var indexerPorts = Projects.Select(p => p.IndexerRpcPort); + + Project = new Project + { + Name = $"CKB Chain", + Chain = Project.ChainType.Dev, + NodeRpcPort = calculatingFromUsed ? rpcPorts.Max() + 3 : 8114, + NodeNetworkPort = calculatingFromUsed ? networkPorts.Max() + 3 : 8115, + IndexerRpcPort = calculatingFromUsed ? indexerPorts.Max() + 3 : 8116, + LockArg = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" }; } @@ -38,16 +49,35 @@ public void OnGet() // To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD public async Task OnPostAsync() { - if (Project.LockArg.StartsWith("ckb") || Project.LockArg.StartsWith("ckt")) - { + if (Project.LockArg.StartsWith("ckb") || Project.LockArg.StartsWith("ckt")) + { Project.LockArg = Address.ParseAddress(Project.LockArg, Project.LockArg.Substring(0, 3)).Args; } + + Project.Tokens = new List(); Project.RecordedTransactions = new List(); Project.IsActive = !Projects.Any(p => p.IsActive); DbContext.Projects.Add(Project); await DbContext.SaveChangesAsync(); + foreach (var item in ConstractFiles) + { + if (item.selectforintockb) + { + DbContext.Contracts.Add(new Contracts + { + ProjectId = Project.Id, + createtime = DateTime.Now, + filename = item.filename, + filepath = item.filepath + }); + } + + } + await DbContext.SaveChangesAsync(); + + return RedirectToPage("./Index"); } } diff --git a/src/Tippy/Pages/Projects/Details.cshtml b/src/Tippy/Pages/Projects/Details.cshtml index 1f45ad6..8346944 100644 --- a/src/Tippy/Pages/Projects/Details.cshtml +++ b/src/Tippy/Pages/Projects/Details.cshtml @@ -15,7 +15,7 @@ - @Html.DisplayFor(model => model.Project.Name) + @Html.DisplayFor(model => model.Project.Name)
diff --git a/src/Tippy/Pages/Projects/Edit.cshtml.cs b/src/Tippy/Pages/Projects/Edit.cshtml.cs index 24e9916..7da2ccc 100644 --- a/src/Tippy/Pages/Projects/Edit.cshtml.cs +++ b/src/Tippy/Pages/Projects/Edit.cshtml.cs @@ -1,6 +1,6 @@ using System.Linq; using System.Threading.Tasks; -using Ckb.Address; +using Ckb.Address; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Tippy.Core.Models; diff --git a/src/Tippy/Pages/Projects/Index.cshtml b/src/Tippy/Pages/Projects/Index.cshtml index a5cc24e..3d6cd12 100644 --- a/src/Tippy/Pages/Projects/Index.cshtml +++ b/src/Tippy/Pages/Projects/Index.cshtml @@ -15,7 +15,7 @@
@foreach (var item in Model.Projects) -{ +{ var className = item.IsActive ? "is-active" : "";
@@ -102,7 +102,7 @@ } - else + else { - - - - - Manage Chains - + +
+ +
+ + + + Manage Chains + + + + + My Constracts +
@@ -103,7 +109,7 @@ @if (Model.ActiveProject != null && ProcessManager.IsRunning(Model.ActiveProject)) - { + {
  • @@ -191,7 +197,7 @@ - + @RenderSection("Scripts", required: false) diff --git a/src/Tippy/Pages/Transactions/Details.cshtml b/src/Tippy/Pages/Transactions/Details.cshtml index b4fc990..88a0aea 100644 --- a/src/Tippy/Pages/Transactions/Details.cshtml +++ b/src/Tippy/Pages/Transactions/Details.cshtml @@ -263,7 +263,7 @@ Lock Script
  • - @{ var lockScript = Model.OutputLockScripts[index]; } + @{ var lockScript = Model.OutputLockScripts[output.RealId]; }
     {
         code_hash: @lockScript.CodeHash,
    @@ -272,7 +272,7 @@
     }
    - @{ var typeScript = Model.OutputTypeScripts[index]; } + @{ var typeScript = Model.OutputTypeScripts[output.RealId]; }
    Type Script
    @@ -328,11 +328,14 @@ }
    -
    - Data +
    + Data +      Cell Index:  @output.RealId +      Hash Value:  @Model.OutputsDataHash[output.RealId]
    -
    @Model.OutputsData[index]
    + +
    @Model.OutputsData[output.RealId]

    diff --git a/src/Tippy/Pages/Transactions/Details.cshtml.cs b/src/Tippy/Pages/Transactions/Details.cshtml.cs index 932ea51..1902163 100644 --- a/src/Tippy/Pages/Transactions/Details.cshtml.cs +++ b/src/Tippy/Pages/Transactions/Details.cshtml.cs @@ -21,6 +21,7 @@ public DetailsModel(Tippy.Core.Data.TippyDbContext context) : base(context) public Transaction Transaction = default!; public TransactionDetailResult TransactionDetail = default!; public List OutputsData = default!; + public List OutputsDataHash = new List(); public List