diff --git a/AElf.Client.Test/ClientTest.cs b/AElf.Client.Test/ClientTest.cs deleted file mode 100644 index 58b6212..0000000 --- a/AElf.Client.Test/ClientTest.cs +++ /dev/null @@ -1,474 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using AElf.Cryptography; -using AElf.Types; -using AElf.Client.Dto; -using AElf.Client.Runtime; -using AElf.Client.Service; -using Google.Protobuf; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Shouldly; -using Volo.Abp.Threading; -using Xunit; -using Xunit.Abstractions; -using Address = AElf.Types.Address; -using Hash = AElf.Types.Hash; - -namespace AElf.Client.Test -{ - public class ClientTest - { - private const string BaseUrl = "Http://127.0.0.1:8200"; - - private string _genesisAddress; - private string GenesisAddress => GetGenesisContractAddress(); - - // example contract-method-name - private string ContractMethodName => "GetContractAddressByName"; - - // Address and privateKey of a node. - private readonly string _address; - private const string PrivateKey = "09da44778f8db2e602fb484334f37df19e221c84c4582ce5b7770ccfbc3ddbef"; - - private AElfClient Client { get; } - private readonly ITestOutputHelper _testOutputHelper; - - public ClientTest(ITestOutputHelper testOutputHelper) - { - _testOutputHelper = testOutputHelper; - Client = new AElfClient(BaseUrl); - - // To get address from privateKey.s - _address = Client.GetAddressFromPrivateKey(PrivateKey); - } - - #region block - - [Fact] - public async Task GetBlockHeightTest() - { - var height = await Client.GetBlockHeightAsync(); - height.ShouldNotBeNull(); - _testOutputHelper.WriteLine(height.ToString()); - } - - [Fact] - public async Task GetBlock_ByHeightAsyncTest() - { - var height = await Client.GetBlockHeightAsync(); - var blockDto = await Client.GetBlockByHeightAsync(height); - Assert.True(blockDto != null); - - var block = JsonConvert.SerializeObject(blockDto, Formatting.Indented); - _testOutputHelper.WriteLine(block); - } - - [Fact] - public async Task GetBlockByHeight_Failed_Test() - { - const int timeOut = 60; - var httpService = new HttpService(timeOut); - const int heightNotExist = int.MaxValue; - var errorResponse = await httpService.GetResponseAsync( - $"{BaseUrl}/api/blockChain/blockByHeight?blockHeight={heightNotExist}&includeTransactions=false", - expectedStatusCode: HttpStatusCode.Forbidden); - errorResponse.Error.Code.ShouldBe(Error.NotFound.ToString()); - errorResponse.Error.Message.ShouldBe(Error.Message[Error.NotFound]); - var str = JsonConvert.SerializeObject(errorResponse, Formatting.Indented); - _testOutputHelper.WriteLine(str); - } - - [Fact] - public async Task GetBlockAsync_Success_Test() - { - var chainStatusDto = await Client.GetChainStatusAsync(); - var genesisHash = chainStatusDto.GenesisBlockHash; - - var blockDto = await Client.GetBlockByHashAsync(genesisHash, true); - Assert.True(blockDto != null); - - var block = JsonConvert.SerializeObject(blockDto, Formatting.Indented); - _testOutputHelper.WriteLine(block); - } - - #endregion - - #region chain - - [Fact] - public async Task GetChainStatusAsync_Test() - { - var chainStatusDto = await Client.GetChainStatusAsync(); - Assert.True(chainStatusDto != null); - - var chainStatus = JsonConvert.SerializeObject(chainStatusDto, Formatting.Indented); - _testOutputHelper.WriteLine(chainStatus); - } - - [Fact] - public async Task GetContractFileDescriptorSetAsync_Test() - { - var contractAddress = GenesisAddress; - var fileDescriptorBytes = await Client.GetContractFileDescriptorSetAsync(contractAddress); - var descriptorSet = FileDescriptorSet.Parser.ParseFrom(fileDescriptorBytes); - descriptorSet.ShouldNotBeNull(); - } - - [Fact(Skip = "Redo this later.")] - public async Task GetCurrentRoundInformationAsync_Test() - { - var webAppService = new AElfClient(BaseUrl, 60); - var roundDto = await webAppService.GetCurrentRoundInformationAsync(); - roundDto.ShouldNotBeNull(); - - var currentRoundInformation = JsonConvert.SerializeObject(roundDto); - _testOutputHelper.WriteLine(currentRoundInformation); - } - - #endregion - - #region net - - /// - /// Work in multiple nodes.(>=2) - /// - /// - [Fact(Skip = "Redo this later.")] - public async Task AddPeerAsync_Test() - { - // add ipAddress - var addressToAdd = "192.168.199.122:7003"; - - var addSuccess = await Client.AddPeerAsync(addressToAdd); - addSuccess.ShouldBeTrue(); - _testOutputHelper.WriteLine($"Added ipAddress: {addressToAdd}"); - } - - [Fact(Skip = "Redo this later.")] - public async Task RemovePeerAsync_Test() - { - var peers = await Client.GetPeersAsync(false); - peers.ShouldNotBeEmpty(); - - var peerToRemoveAddress = peers[0].IpAddress; - var removeSuccess = await Client.RemovePeerAsync(peerToRemoveAddress); - Assert.True(removeSuccess); - _testOutputHelper.WriteLine($"Removed ipAddress: {peerToRemoveAddress}"); - } - - [Fact] - public async Task GetPeersAsync_Test() - { - var peers = await Client.GetPeersAsync(false); - Assert.True(peers != null); - var peersInfo = JsonConvert.SerializeObject(peers, Formatting.Indented); - _testOutputHelper.WriteLine(peersInfo); - } - - [Fact] - public async Task GetNetworkInfoAsync_Test() - { - var netWorkInfo = await Client.GetNetworkInfoAsync(); - Assert.True(netWorkInfo != null); - var info = JsonConvert.SerializeObject(netWorkInfo, Formatting.Indented); - _testOutputHelper.WriteLine(info); - } - - #endregion - - #region transaction - - [Fact] - public async Task GetTaskQueueStatusAsync_Test() - { - var taskQueueStatus = await Client.GetTaskQueueStatusAsync(); - taskQueueStatus.ShouldNotBeEmpty(); - - var queueStatus = JsonConvert.SerializeObject(taskQueueStatus, Formatting.Indented); - _testOutputHelper.WriteLine(queueStatus); - } - - [Fact] - public async Task GetTransactionPoolStatusAsync_Test() - { - var poolStatus = await Client.GetTransactionPoolStatusAsync(); - Assert.True(poolStatus != null); - - var status = JsonConvert.SerializeObject(poolStatus, Formatting.Indented); - _testOutputHelper.WriteLine(status); - } - - [Fact] - public async Task ExecuteTransactionAsync_Test() - { - var toAddress = GenesisAddress; - var methodName = ContractMethodName; - var param = Hash.FromString("AElf.ContractNames.TokenConverter"); - - var transaction = await Client.GenerateTransaction(_address, toAddress, methodName, param); - var txWithSign = Client.SignTransaction(PrivateKey, transaction); - - var transactionResult = await Client.ExecuteTransactionAsync(new ExecuteTransactionDto - { - RawTransaction = txWithSign.ToByteArray().ToHex() - }); - Assert.True(transactionResult != null); - - var addressResult = Address.Parser.ParseFrom(ByteArrayHelper.HexStringToByteArray(transactionResult)); - var address = await Client.GetContractAddressByName(param); - Assert.True(address == addressResult); - } - - [Fact] - public async Task CreateRawTransactionAsync_Test() - { - var address = GenesisAddress; - var status = await Client.GetChainStatusAsync(); - var height = status.BestChainHeight; - var blockHash = status.BestChainHash; - - var createRaw = await Client.CreateRawTransactionAsync(new CreateRawTransactionInput - { - From = _address, - To = address, - MethodName = ContractMethodName, - Params = new JObject - { - ["value"] = Hash.FromString("AElf.ContractNames.Token").Value.ToBase64() - }.ToString(), - RefBlockNumber = height, - RefBlockHash = blockHash - }); - - createRaw.RawTransaction.ShouldNotBeEmpty(); - } - - [Fact] - public async Task ExecuteRawTransactionAsync_Test() - { - var address = GenesisAddress; - var status = await Client.GetChainStatusAsync(); - var height = status.BestChainHeight; - var blockHash = status.BestChainHash; - - var createRaw = await Client.CreateRawTransactionAsync(new CreateRawTransactionInput - { - From = _address, - To = address, - MethodName = ContractMethodName, - Params = new JObject - { - ["value"] = Hash.FromString("AElf.ContractNames.Consensus").Value.ToBase64() - }.ToString(), - RefBlockNumber = height, - RefBlockHash = blockHash - }); - - var transactionId = Hash.FromRawBytes(ByteArrayHelper.HexStringToByteArray(createRaw.RawTransaction)); - var signature = GetSignatureWith(PrivateKey, transactionId.ToByteArray()).ToHex(); - var rawTransactionResult = await Client.ExecuteRawTransactionAsync(new ExecuteRawTransactionDto - { - RawTransaction = createRaw.RawTransaction, - Signature = signature - }); - - rawTransactionResult.ShouldNotBeEmpty(); - var consensusAddress = - (await Client.GetContractAddressByName(Hash.FromString("AElf.ContractNames.Consensus"))) - .GetFormatted(); - - Assert.True(rawTransactionResult == $"\"{consensusAddress}\""); - } - - [Fact] - public async Task SendRawTransactionAsync_Test() - { - var toAddress = GenesisAddress; - var status = await Client.GetChainStatusAsync(); - var height = status.BestChainHeight; - var blockHash = status.BestChainHash; - - var createRaw = await Client.CreateRawTransactionAsync(new CreateRawTransactionInput - { - From = _address, - To = toAddress, - MethodName = ContractMethodName, - Params = new JObject - { - ["value"] = Hash.FromString("AElf.ContractNames.Token").Value.ToBase64() - }.ToString(), - RefBlockNumber = height, - RefBlockHash = blockHash - }); - createRaw.RawTransaction.ShouldNotBeEmpty(); - - var transactionId = Hash.FromRawBytes(ByteArrayHelper.HexStringToByteArray(createRaw.RawTransaction)); - var signature = GetSignatureWith(PrivateKey, transactionId.ToByteArray()).ToHex(); - - var rawTransactionResult = await Client.SendRawTransactionAsync(new SendRawTransactionInput - { - Transaction = createRaw.RawTransaction, - Signature = signature, - ReturnTransaction = true - }); - - Assert.True(rawTransactionResult != null); - - var result = JsonConvert.SerializeObject(rawTransactionResult, Formatting.Indented); - _testOutputHelper.WriteLine(result); - } - - [Fact] - public async Task SendTransactionAsync_Test() - { - var toAddress = GenesisAddress; - var methodName = ContractMethodName; - var param = Hash.FromString("AElf.ContractNames.Vote"); - - var transaction = await Client.GenerateTransaction(_address, toAddress, methodName, param); - var txWithSign = Client.SignTransaction(PrivateKey, transaction); - - var result = await Client.SendTransactionAsync(new SendTransactionInput - { - RawTransaction = txWithSign.ToByteArray().ToHex() - }); - - result.ShouldNotBeNull(); - _testOutputHelper.WriteLine(result.TransactionId); - } - - [Fact] - public async Task SendTransactionsAsync_Test() - { - var toAddress = GenesisAddress; - var methodName = ContractMethodName; - var param1 = Hash.FromString("AElf.ContractNames.Token"); - var param2 = Hash.FromString("AElf.ContractNames.Vote"); - - var parameters = new List {param1, param2}; - var transactions = new List(); - - foreach (var param in parameters) - { - var tx = await Client.GenerateTransaction(_address, toAddress, methodName, param); - var txWithSign = Client.SignTransaction(PrivateKey, tx); - - transactions.Add(txWithSign); - } - - var result1 = await Client.SendTransactionAsync(new SendTransactionInput - { - RawTransaction = transactions[0].ToByteArray().ToHex() - }); - - Assert.True(result1 != null); - - var result2 = await Client.SendTransactionAsync(new SendTransactionInput - { - RawTransaction = transactions[1].ToByteArray().ToHex() - }); - - Assert.True(result2 != null); - _testOutputHelper.WriteLine(result1.TransactionId + "\r\n" + result2.TransactionId); - } - - [Fact] - public async Task GetTransactionResultAsync_Test() - { - var firstBlockDto = await Client.GetBlockByHeightAsync(1, true); - var transactionId = firstBlockDto.Body.Transactions.FirstOrDefault(); - - var transactionResultDto = await Client.GetTransactionResultAsync(transactionId); - Assert.True(transactionResultDto.Status == TransactionResultStatus.Mined.ToString().ToUpper()); - } - - [Fact] - public async Task GetTransactionResultsAsync_Test() - { - var firstBlockDto = await Client.GetBlockByHeightAsync(1, true); - var blockHash = firstBlockDto.BlockHash; - - var transactionResults = await Client.GetTransactionResultsAsync(blockHash, 0, 2); - foreach (var transaction in transactionResults) - { - Assert.True(transaction.Status == TransactionResultStatus.Mined.ToString()); - } - } - - [Fact] - public async Task GetMerklePathByTransactionIdAsync_Test() - { - var firstBlockDto = await Client.GetBlockByHeightAsync(1, true); - var transactionId = firstBlockDto.Body.Transactions.FirstOrDefault(); - var merklePathDto = await Client.GetMerklePathByTransactionIdAsync(transactionId); - Assert.True(merklePathDto != null); - - var merklePath = JsonConvert.SerializeObject(merklePathDto, Formatting.Indented); - merklePath.ShouldNotBeEmpty(); - - _testOutputHelper.WriteLine(merklePath); - } - - [Fact] - public async Task GetChainIdAsync_Test() - { - var chainId = await Client.GetChainIdAsync(); - chainId.ShouldNotBeNull(); - chainId.ShouldBeOfType(typeof(int)); - - _testOutputHelper.WriteLine(chainId.ToString()); - } - - [Fact] - public async Task IsConnected_Test() - { - var isConnected = await Client.IsConnected(); - isConnected.ShouldBeTrue(); - } - - [Fact] - public async Task GetGenesisContractAddressAsync_Test() - { - var genesisAddress = await Client.GetGenesisContractAddressAsync(); - genesisAddress.ShouldNotBeEmpty(); - - var address = await Client.GetContractAddressByName(Hash.Empty); - var genesisAddress2 = address.GetFormatted(); - Assert.True(genesisAddress == genesisAddress2); - } - - [Fact] - public async Task GetFormattedAddress_Test() - { - var result = await Client.GetFormattedAddress(AddressHelper.Base58StringToAddress(_address)); - _testOutputHelper.WriteLine(result); - Assert.True(result == $"ELF_{_address}_AELF"); - } - - #endregion - - #region private methods - - private string GetGenesisContractAddress() - { - if (_genesisAddress != null) return _genesisAddress; - - var statusDto = AsyncHelper.RunSync(Client.GetChainStatusAsync); - _genesisAddress = statusDto.GenesisContractAddress; - - return _genesisAddress; - } - - private ByteString GetSignatureWith(string privateKey, byte[] txData) - { - // Sign the hash - var signature = CryptoHelper.SignWithPrivateKey(ByteArrayHelper.HexStringToByteArray(privateKey), txData); - return ByteString.CopyFrom(signature); - } - - #endregion - } -} \ No newline at end of file diff --git a/AElf.Client.sln b/AElf.Client.sln deleted file mode 100644 index 84d1498..0000000 --- a/AElf.Client.sln +++ /dev/null @@ -1,30 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client", "AElf.Client\AElf.Client.csproj", "{8812E67B-3177-4370-B8FE-7D9C77CDAACD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Test", "AElf.Client.Test\AElf.Client.Test.csproj", "{5201BCB2-AF90-408F-A830-9879B889C89A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3149BCAC-24BE-469C-88A5-139680B4DE1E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1FF8D171-87A5-4D4C-B8B4-82F0B4D9260D}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8812E67B-3177-4370-B8FE-7D9C77CDAACD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8812E67B-3177-4370-B8FE-7D9C77CDAACD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8812E67B-3177-4370-B8FE-7D9C77CDAACD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8812E67B-3177-4370-B8FE-7D9C77CDAACD}.Release|Any CPU.Build.0 = Release|Any CPU - {5201BCB2-AF90-408F-A830-9879B889C89A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5201BCB2-AF90-408F-A830-9879B889C89A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5201BCB2-AF90-408F-A830-9879B889C89A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5201BCB2-AF90-408F-A830-9879B889C89A}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {5201BCB2-AF90-408F-A830-9879B889C89A} = {3149BCAC-24BE-469C-88A5-139680B4DE1E} - {8812E67B-3177-4370-B8FE-7D9C77CDAACD} = {1FF8D171-87A5-4D4C-B8B4-82F0B4D9260D} - EndGlobalSection -EndGlobal diff --git a/AElf.Client/AElf.Client.csproj b/AElf.Client/AElf.Client.csproj deleted file mode 100644 index 29af607..0000000 --- a/AElf.Client/AElf.Client.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - netcoreapp3.0 - AElf.Client - This is a C# client library, used to communicate with the AElf API. - AElf - true - - - - - - - - - - - - - - - - - - - - - none - PreserveNewest - ./Protobuf/Generated - ./Protobuf/Generated - Protobuf/Proto - - - diff --git a/AElf.Client/Dto/CreateRawTransactionInput.cs b/AElf.Client/Dto/CreateRawTransactionInput.cs deleted file mode 100644 index 3dc6d58..0000000 --- a/AElf.Client/Dto/CreateRawTransactionInput.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; - -namespace AElf.Client.Dto -{ - public class CreateRawTransactionInput : IValidatableObject - { - /// - /// from address - /// - [Required] - public string From { get; set; } - - /// - /// to address - /// - [Required] - public string To { get; set; } - - /// - /// refer block height - /// - [Required] - public long RefBlockNumber { get; set; } - - /// - /// refer block hash - /// - [Required] - public string RefBlockHash { get; set; } - - /// - /// contract method name - /// - [Required] - public string MethodName { get; set; } - - /// - /// contract method parameters - /// - [Required] - public string Params { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) - { - var validationResults = new List(); - try - { - AddressHelper.Base58StringToAddress(From); - } - catch - { - validationResults.Add(new ValidationResult(Error.Message[Error.InvalidAddress], - new[] {nameof(From)})); - } - - try - { - AddressHelper.Base58StringToAddress(To); - } - catch - { - validationResults.Add( - new ValidationResult(Error.Message[Error.InvalidAddress], new[] {nameof(To)})); - } - - try - { - HashHelper.HexStringToHash(RefBlockHash); - } - catch - { - validationResults.Add( - new ValidationResult(Error.Message[Error.InvalidBlockHash], new[] {nameof(RefBlockHash)})); - } - - return validationResults; - } - } -} \ No newline at end of file diff --git a/AElf.Client/Dto/CurrentRoundInformationDto.cs b/AElf.Client/Dto/CurrentRoundInformationDto.cs deleted file mode 100644 index 94680b6..0000000 --- a/AElf.Client/Dto/CurrentRoundInformationDto.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace AElf.Client.Dto -{ - public class RoundDto - { - public long RoundNumber { get; set; } - public long TermNumber { get; set; } - public long RoundId { get; set; } - public Dictionary RealTimeMinerInformation { get; set; } - public string ExtraBlockProducerOfPreviousRound { get; set; } - public long ConfirmedIrreversibleBlockRoundNumber { get; set; } - public long ConfirmedIrreversibleBlockHeight { get; set; } - public bool IsMinerListJustChanged { get; set; } - } - - public class MinerInRoundDto - { - public int Order { get; set; } - public int ProducedTinyBlocks { get; set; } - public DateTime ExpectedMiningTime { get; set; } - public List ActualMiningTimes { get; set; } - public string InValue { get; set; } - public string PreviousInValue { get; set; } - public string OutValue { get; set; } - public long ProducedBlocks { get; set; } - public long MissedBlocks { get; set; } - public long ImpliedIrreversibleBlockHeight { get; set; } - } -} \ No newline at end of file diff --git a/AElf.Client/Dto/TransactionFeeDto.cs b/AElf.Client/Dto/TransactionFeeDto.cs deleted file mode 100644 index 27c22a1..0000000 --- a/AElf.Client/Dto/TransactionFeeDto.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace AElf.Client.Dto -{ - public class TransactionFeeDto - { - public Dictionary Value { get; set; } - } -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/aedpos_contract.proto b/AElf.Client/Protobuf/Proto/aedpos_contract.proto deleted file mode 100644 index bdda35a..0000000 --- a/AElf.Client/Protobuf/Proto/aedpos_contract.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "AElf.Client.Consensus.AEDPoS"; - -//aedpos_contract -message MinerList { - repeated bytes pubkeys = 1; -} - -message PubkeyList { - repeated string pubkeys = 1; -} - -message MinerListWithRoundNumber { - MinerList miner_list = 1; - sint64 round_number = 2; -} - -message GetMinerListInput { - sint64 term_number = 1; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/association_auth_contract.proto b/AElf.Client/Protobuf/Proto/association_auth_contract.proto deleted file mode 100644 index 3d5f201..0000000 --- a/AElf.Client/Protobuf/Proto/association_auth_contract.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; - -import "client.proto"; - -option csharp_namespace = "AElf.Client.AssociationAuth"; - -// association_auth_contract -message Organization{ - int32 release_threshold = 1; - repeated Reviewer reviewers = 2; - int32 proposer_threshold = 3; - client.Address organization_address = 4; - client.Hash organization_hash = 5; -} - -message Reviewer { - client.Address address = 1; - int32 weight = 2; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/basic_contract_zero.proto b/AElf.Client/Protobuf/Proto/basic_contract_zero.proto deleted file mode 100644 index a6f1561..0000000 --- a/AElf.Client/Protobuf/Proto/basic_contract_zero.proto +++ /dev/null @@ -1,10 +0,0 @@ -syntax = "proto3"; - -import "client.proto"; - -option csharp_namespace = "AElf.Client.Genesis"; - -//basic_contract_zero -message AddressList { - repeated client.Address value = 1; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/client.proto b/AElf.Client/Protobuf/Proto/client.proto deleted file mode 100644 index bde9631..0000000 --- a/AElf.Client/Protobuf/Proto/client.proto +++ /dev/null @@ -1,166 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "AElf.Client.Proto"; - -package client; - -import "google/protobuf/timestamp.proto"; - -message Address -{ - bytes value = 1; -} - -message Hash -{ - bytes value = 1; -} - -message MerklePath { - repeated MerklePathNode merkle_path_nodes = 1; -} - -message MerklePathNode{ - Hash hash = 1; - bool is_left_child_node = 2; -} - -message BinaryMerkleTree { - repeated Hash nodes = 1; - Hash root = 2; - int32 leaf_count = 3; -} - -message ScopedStatePath { - Address address = 1; - StatePath path = 2; -} - -message StatePath { - repeated string parts = 1; -} - -message SmartContractRegistration { - int32 category = 1; - bytes code = 2; - Hash code_hash = 3; -} - -//acs0 -message ContractInfo -{ - uint64 serial_number = 1; - int32 category = 3; - Hash code_hash = 4; - bool is_system_contract = 5; -} - -//acs1 -message MethodFees { - string method_name = 1; - repeated MethodFee fees = 2; -} - -message MethodFee { - string symbol = 1; - sint64 basic_fee = 2; -} - -//acs2 -message ResourceInfo { - repeated ScopedStatePath paths = 1; - bool non_parallelizable = 2; -} - -// acs3 -message ProposalOutput { - Hash proposal_id = 1; - string contract_method_name = 2; - Address to_address = 3; - bytes params = 4; - google.protobuf.Timestamp expired_time = 5; - Address organization_address = 6; - Address proposer = 7; - bool to_be_released = 8; -} - -//acs4 - -message ValidationResult { - bool success = 1; - string message = 2; -} - -//acs5 -message MethodCallingThreshold { - map symbol_to_amount = 1;// The order matters. - ThresholdCheckType threshold_check_type = 2; -} - -enum ThresholdCheckType { - BALANCE = 0; - ALLOWANCE = 1; -} - -//acs7 -message SideChainIdAndHeightDict { - map id_height_dict = 1; -} - -message SideChainIndexingInformationList { - repeated SideChainIndexingInformation indexing_information_list = 1; -} - -message SideChainIndexingInformation { - int32 chain_id = 1; - int64 indexed_height = 2; - int64 to_be_indexed_count = 3; -} - -message CrossChainBlockData { - repeated SideChainBlockData side_chain_block_data = 1; - repeated ParentChainBlockData parent_chain_block_data = 2; - int64 previous_block_height = 3; -} - -message SideChainBlockData { - int64 height = 1; - Hash block_header_hash = 2; - Hash transaction_status_merkle_tree_root = 3; - int32 chain_id = 4; -} - -message ParentChainBlockData { - int64 height = 1; - CrossChainExtraData cross_chain_extra_data = 2; - int32 chain_id = 3; - Hash transaction_status_merkle_tree_root = 4; - - // Indexed block height from side chain and merkle path for this side chain block - map indexed_merkle_path = 5; - map extra_data = 6; -} - -message CrossChainExtraData { - // Merkle tree root of side chain block transaction status root - Hash transaction_status_merkle_tree_root = 1; -} - -message IndexedSideChainBlockData{ - repeated SideChainBlockData side_chain_block_data = 1; -} - -message CrossChainMerkleProofContext { - int64 bound_parent_chain_height = 1; - MerklePath merkle_path_from_parent_chain = 2; -} - -message ChainInitializationData { - int32 chain_id = 1; - Address creator = 2; - google.protobuf.Timestamp creation_timestamp = 3; - repeated bytes extra_information = 4; - int64 creation_height_on_parent_chain = 5; - bool chain_creator_privilege_preserved = 6; - string side_chain_token_symbol = 7; -} diff --git a/AElf.Client/Protobuf/Proto/cross_chain_contract.proto b/AElf.Client/Protobuf/Proto/cross_chain_contract.proto deleted file mode 100644 index 9babbaa..0000000 --- a/AElf.Client/Protobuf/Proto/cross_chain_contract.proto +++ /dev/null @@ -1,13 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "AElf.Client.CrossChain"; - -import "client.proto"; - -//cross_chain_contract -message VerifyTransactionInput { - client.Hash transaction_id = 1; - client.MerklePath path = 2; - sint64 parent_chain_height = 3; - int32 verified_chain_id = 4; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/descriptor_equivalent.proto b/AElf.Client/Protobuf/Proto/descriptor_equivalent.proto deleted file mode 100644 index fa6bae6..0000000 --- a/AElf.Client/Protobuf/Proto/descriptor_equivalent.proto +++ /dev/null @@ -1,8 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "AElf.Client.Runtime"; - -//fileDescriptor_equivalent -message FileDescriptorSet { - repeated bytes file = 1; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/election_contract.proto b/AElf.Client/Protobuf/Proto/election_contract.proto deleted file mode 100644 index bb86cd8..0000000 --- a/AElf.Client/Protobuf/Proto/election_contract.proto +++ /dev/null @@ -1,99 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "AElf.Client.Election"; - -import "google/protobuf/timestamp.proto"; -import "client.proto"; - -//election_contract -message CandidateInformation { - string pubkey = 1; - repeated sint64 terms = 2; - sint64 produced_blocks = 3; - sint64 missed_time_slots = 4; - sint64 continual_appointment_count = 5; - client.Hash announcement_transaction_id = 6; - bool is_current_candidate = 7; -} - -message GetTermSnapshotInput { - sint64 term_number = 1; -} - -message TermSnapshot { - sint64 end_round_number = 1; - sint64 mined_blocks = 2; - map election_result = 3; -} - -message GetElectionResultInput { - sint64 term_number = 1; -} - -message ElectionResult { - sint64 term_number = 1; - map results = 2; - bool is_active = 3; -} - -message ElectorVote { - repeated client.Hash active_voting_record_ids = 1;// Not withdrawn. - repeated client.Hash withdrawn_voting_record_ids = 2; - sint64 active_voted_votes_amount = 3; - sint64 all_voted_votes_amount = 4; - repeated ElectionVotingRecord active_voting_records = 5; - repeated ElectionVotingRecord withdrawn_votes_records = 6; - bytes pubkey = 7; -} - -message ElectionVotingRecord { - client.Address voter = 1; - string candidate = 2; - sint64 amount = 3; - sint64 term_number = 4; - client.Hash vote_id = 5; - sint64 lock_time = 7; - google.protobuf.Timestamp unlock_timestamp = 10; - google.protobuf.Timestamp withdraw_timestamp = 11; - google.protobuf.Timestamp vote_timestamp = 12; - bool is_withdrawn = 13; - sint64 weight = 14; - bool is_change_target = 15; -} - -message CandidateVote { - repeated client.Hash obtained_active_voting_record_ids = 1; - repeated client.Hash obtained_withdrawn_voting_record_ids = 2; - sint64 obtained_active_voted_votes_amount = 3; - sint64 all_obtained_voted_votes_amount = 4; - repeated ElectionVotingRecord obtained_active_voting_records = 5; - repeated ElectionVotingRecord obtained_withdrawn_votes_records = 6; - bytes pubkey = 7; -} - -message GetWelfareRewardAmountSampleInput { - repeated sint64 value = 1; -} - -message GetWelfareRewardAmountSampleOutput { - repeated sint64 value = 1; -} - -message PageInformation { - sint32 start = 1; - sint32 length = 2; -} - -message CandidateDetail { - CandidateInformation candidate_information = 1; - sint64 obtained_votes_amount = 2; -} - -message GetPageableCandidateInformationOutput { - repeated CandidateDetail value = 1; -} - -message DataCenterRankingList { - map data_centers = 1; - sint64 minimum_votes = 2; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/parliament_auth_contract.proto b/AElf.Client/Protobuf/Proto/parliament_auth_contract.proto deleted file mode 100644 index 512c1a4..0000000 --- a/AElf.Client/Protobuf/Proto/parliament_auth_contract.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; - -import "client.proto"; - -option csharp_namespace = "AElf.Client.ParliamentAuth"; - -//parliament_auth -message ProposalIdList{ - repeated client.Hash proposal_ids = 1; -} - -message Organization { - sint32 release_threshold = 1; - client.Address organization_address = 2; - client.Hash organization_hash = 3; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/profit_contract.proto b/AElf.Client/Protobuf/Proto/profit_contract.proto deleted file mode 100644 index c6178cd..0000000 --- a/AElf.Client/Protobuf/Proto/profit_contract.proto +++ /dev/null @@ -1,66 +0,0 @@ -syntax = "proto3"; - -import "client.proto"; - -option csharp_namespace = "AElf.Client.Profit"; - -//profit_contract -message CreatedSchemeIds { - repeated client.Hash scheme_ids = 1; -} - -message GetManagingSchemeIdsInput { - client.Address manager = 1; -} - -message SchemeBeneficiaryShare { - client.Hash scheme_id = 1; - sint64 shares = 2; -} - -message Scheme { - client.Address virtual_address = 1; - sint64 total_shares = 2; - map undistributed_profits = 3;// token symbol -> amount - sint64 current_period = 4; - repeated SchemeBeneficiaryShare sub_schemes = 5; - sint64 profit_receiving_due_period_count = 7; - bool is_release_all_balance_every_time_by_default = 8; - client.Hash scheme_id = 9; - sint32 delay_distribute_period_count = 10; - map cached_delay_total_shares = 11;// period -> total shares, max elements count should be delay_distribute_period_count - client.Address manager = 12; -} - -message SchemePeriod { - client.Hash scheme_id = 1; - sint64 period = 2; -} - -message DistributedProfitsInfo { - sint64 total_shares = 1; - map profits_amount = 2; - bool is_released = 3; -} - -message GetProfitDetailsInput { - client.Hash scheme_id = 1; - client.Address beneficiary = 2; -} - -message ProfitDetails { - repeated ProfitDetail details = 1; -} - -message ProfitDetail { - sint64 start_period = 1; - sint64 end_period = 2; - sint64 shares = 3; - sint64 last_profit_period = 4; - bool is_weight_removed = 5; -} - -message ClaimProfitsInput { - client.Hash scheme_id = 1; - string symbol = 2; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/referendum_auth_contract.proto b/AElf.Client/Protobuf/Proto/referendum_auth_contract.proto deleted file mode 100644 index 1fba552..0000000 --- a/AElf.Client/Protobuf/Proto/referendum_auth_contract.proto +++ /dev/null @@ -1,12 +0,0 @@ -syntax = "proto3"; - -import "client.proto"; - -option csharp_namespace = "AElf.Client.ReferendumAuth"; - -message Organization { - int64 release_threshold = 1; - string token_symbol = 2; - client.Address organization_address = 3; - client.Hash organization_hash = 4; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/resource_contract.proto b/AElf.Client/Protobuf/Proto/resource_contract.proto deleted file mode 100644 index 6e759cb..0000000 --- a/AElf.Client/Protobuf/Proto/resource_contract.proto +++ /dev/null @@ -1,30 +0,0 @@ -syntax = "proto3"; - -import "client.proto"; - -option csharp_namespace = "AElf.Client.Resource"; - -message ResourceId { - ResourceType type = 1; -} - -enum ResourceType { - UNDEFINED_RESOURCE_TYPE = 0; - RAM = 1; - CPU = 2; - NET = 3; - STO = 4; -} - -message Converter { - sint64 res_balance = 1; - sint64 elf_balance = 2; - sint64 res_weight = 3; // Weight based on MAX of 1,000,000 - sint64 elf_weight = 4; // Weight based on MAX of 1,000,000 - ResourceType type = 5; -} - -message UserResourceId { - client.Address address = 1; - ResourceType type = 2; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/toekn_converter_contract.proto b/AElf.Client/Protobuf/Proto/toekn_converter_contract.proto deleted file mode 100644 index 6882c4a..0000000 --- a/AElf.Client/Protobuf/Proto/toekn_converter_contract.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "AElf.Client.TokenConverter"; - -//token converter -message TokenSymbol { - string symbol = 1; -} - -message Connector { - string symbol = 1; - sint64 virtual_balance = 2; - string weight = 3; - bool is_virtual_balance_enabled = 4; // true if virtual balance is enabled, false if not - bool is_purchase_enabled = 5; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/token_contract.proto b/AElf.Client/Protobuf/Proto/token_contract.proto deleted file mode 100644 index d696c1f..0000000 --- a/AElf.Client/Protobuf/Proto/token_contract.proto +++ /dev/null @@ -1,86 +0,0 @@ -syntax = "proto3"; - -import "client.proto"; - -option csharp_namespace = "AElf.Client.MultiToken"; - -//tokenContract -message TokenInfo { - string symbol = 1; - string tokenName = 2; - sint64 supply = 3; - sint64 totalSupply = 4; - sint32 decimals = 5; - client.Address issuer = 6; - bool is_burnable = 7; - bool is_transfer_disabled = 8; - sint32 issue_chain_id = 9; - sint64 burned = 10; -} - -message GetTokenInfoInput { - string symbol = 1; -} - -message TokenInfoList { - repeated TokenInfo value = 1; -} - -message GetBalanceInput { - string symbol = 1; - client.Address owner = 2; -} - -message GetBalanceOutput { - string symbol = 1; - client.Address owner = 2; - sint64 balance = 3; -} - -message GetAllowanceInput { - string symbol = 1; - client.Address owner = 2; - client.Address spender = 3; -} - -message GetAllowanceOutput { - string symbol = 1; - client.Address owner = 2; - client.Address spender = 3; - sint64 allowance = 4; -} - -message IsInWhiteListInput { - string symbol = 1; - client.Address address = 2; -} - -message ProfitReceivingInformation { - client.Address contract_address = 1; - client.Address profit_receiver_address = 2; - sint32 donation_parts_per_hundred = 3; -} - -message GetLockedAmountInput { - client.Address address = 1; - string symbol = 3; - client.Hash lock_id = 4; -} - -message GetLockedAmountOutput { - client.Address address = 1; - string symbol = 3; - client.Hash lock_id = 4; - sint64 amount = 5; -} - -message GetVirtualAddressForLockingInput { - client.Address address = 1; - client.Hash lock_id = 3; -} - -message GetCrossChainTransferTokenContractAddressInput { - int32 chainId = 1; -} - - diff --git a/AElf.Client/Protobuf/Proto/treasury_contract.proto b/AElf.Client/Protobuf/Proto/treasury_contract.proto deleted file mode 100644 index 31a93ee..0000000 --- a/AElf.Client/Protobuf/Proto/treasury_contract.proto +++ /dev/null @@ -1,12 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "AElf.Client.Treasury"; - -//treasury_contract -message GetWelfareRewardAmountSampleInput { - repeated sint64 value = 1; -} - -message GetWelfareRewardAmountSampleOutput { - repeated sint64 value = 1; -} \ No newline at end of file diff --git a/AElf.Client/Protobuf/Proto/vote_contract.proto b/AElf.Client/Protobuf/Proto/vote_contract.proto deleted file mode 100644 index 97ae0af..0000000 --- a/AElf.Client/Protobuf/Proto/vote_contract.proto +++ /dev/null @@ -1,54 +0,0 @@ -syntax = "proto3"; - -import "client.proto"; -import "google/protobuf/timestamp.proto"; - -option csharp_namespace = "AElf.Client.Vote"; - -message GetVotingItemInput { - client.Hash voting_item_id = 1; -} - -message VotedItems { - map voted_item_vote_ids = 1; -} - -message VotedIds { - repeated client.Hash active_votes = 1; - repeated client.Hash withdrawn_votes = 2; -} - -message GetVotingResultInput { - client.Hash voting_item_id = 1; - sint64 snapshot_number = 2; -} - -message VotingResult { - client.Hash voting_item_id = 1; - map results = 2; // option -> amount - sint64 snapshot_number = 3; - sint64 voters_count = 4; - google.protobuf.Timestamp snapshot_start_timestamp = 5; - google.protobuf.Timestamp snapshot_end_timestamp = 6; - sint64 votes_amount = 7; -} - -message VotingRecord { - client.Hash voting_item_id = 1; - client.Address voter = 2; - sint64 snapshot_number = 3; - sint64 amount = 4; - google.protobuf.Timestamp withdraw_timestamp = 5; - google.protobuf.Timestamp vote_timestamp = 6; - bool is_withdrawn = 7; - string option = 8; - bool is_change_target = 9; -} - -message GetVotingRecordsInput { - repeated client.Hash ids = 1; -} - -message VotingRecords { - repeated VotingRecord records = 1; -} diff --git a/AElf.Client/Service/AElfClient.cs b/AElf.Client/Service/AElfClient.cs deleted file mode 100644 index 88c13f4..0000000 --- a/AElf.Client/Service/AElfClient.cs +++ /dev/null @@ -1,265 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using AElf.Client.Dto; -using AElf.Cryptography; -using AElf.Cryptography.ECDSA; -using AElf.Types; -using Google.Protobuf; -using Google.Protobuf.WellKnownTypes; -using Address = AElf.Types.Address; -using Hash = AElf.Types.Hash; - -namespace AElf.Client.Service -{ - public interface IClientService - { - Task IsConnected(); - Task GetFormattedAddress(Address address); - Task GetGenesisContractAddressAsync(); - Task
GetContractAddressByName(Hash contractNameHash); - string GetAddressFromPubKey(string pubKey); - } - - public partial class AElfClient : IClientService - { - private readonly IHttpService _httpService; - private string _baseUrl; - - public string BaseUrl - { - get => _baseUrl; - set => _baseUrl = value; - } - - private const string ExamplePrivateKey = "09da44778f8db2e602fb484334f37df19e221c84c4582ce5b7770ccfbc3ddbef"; - - public AElfClient(string baseUrl, int timeOut = 60) - { - _httpService = new HttpService(timeOut); - _baseUrl = baseUrl; - - } - - /// - /// Verify whether this sdk successfully connects the chain. - /// - /// IsConnected or not - public async Task IsConnected() - { - try - { - var chainStatus = await GetChainStatusAsync(); - return chainStatus != null; - } - catch (Exception) - { - return false; - } - } - - /// - /// Get the address of genesis contract. - /// - /// Address - public async Task GetGenesisContractAddressAsync() - { - var statusDto = await GetChainStatusAsync(); - var genesisAddress = statusDto.GenesisContractAddress; - - return genesisAddress; - } - - /// - /// Get address of a contract by given contractNameHash. - /// - /// - /// - /// Address - public async Task
GetContractAddressByName(Hash contractNameHash) - { - var from = GetAddressFromPrivateKey(ExamplePrivateKey); - var to = await GetGenesisContractAddressAsync(); - var transaction = await GenerateTransaction(from, to, "GetContractAddressByName", contractNameHash); - var txWithSig = SignTransaction(ExamplePrivateKey, transaction); - - var response = await ExecuteTransactionAsync(new ExecuteTransactionDto - { - RawTransaction = txWithSig.ToByteArray().ToHex() - }); - var byteArray = ByteArrayHelper.HexStringToByteArray(response); - var address = Address.Parser.ParseFrom(byteArray); - - return address; - } - - /// - /// Build a transaction from the input parameters. - /// - /// - /// - /// - /// - /// Transaction unsigned - public async Task GenerateTransaction(string from, string to, - string methodName, IMessage input) - { - try - { - AssertValidAddress(from, to); - var chainStatus = await GetChainStatusAsync(); - var transaction = new Transaction - { - From = AddressHelper.Base58StringToAddress(from), - To = AddressHelper.Base58StringToAddress(to), - MethodName = methodName, - Params = input.ToByteString(), - RefBlockNumber = chainStatus.BestChainHeight, - RefBlockPrefix = ByteString.CopyFrom(HashHelper.HexStringToHash(chainStatus.BestChainHash).Value - .Take(4).ToArray()) - }; - - return transaction; - } - catch (Exception) - { - return null; - } - } - - /// - /// Convert the Address to the displayed string:symbol_base58-string_base58-string-chain-id - /// - /// - /// - public async Task GetFormattedAddress(Address address) - { - var tokenContractAddress = await GetContractAddressByName(Hash.FromString("AElf.ContractNames.Token")); - var fromAddress = GetAddressFromPrivateKey(ExamplePrivateKey); - var toAddress = tokenContractAddress.GetFormatted(); - var methodName = "GetPrimaryTokenSymbol"; - var param = new Empty(); - - var transaction = await GenerateTransaction(fromAddress, toAddress, methodName, param); - var txWithSign = SignTransaction(ExamplePrivateKey, transaction); - - var result = await ExecuteTransactionAsync(new ExecuteTransactionDto - { - RawTransaction = txWithSign.ToByteArray().ToHex() - }); - - var symbol = StringValue.Parser.ParseFrom(ByteArrayHelper.HexStringToByteArray(result)); - var chainIdString = (await GetChainStatusAsync()).ChainId; - - return $"{symbol.Value}_{address.GetFormatted()}_{chainIdString}"; - } - - /// - /// Sign a transaction using private key. - /// - /// - /// - /// Transaction signed - public Transaction SignTransaction(string privateKeyHex, Transaction transaction) - { - var transactionData = transaction.GetHash().ToByteArray(); - - // Sign the hash - var privateKey = ByteArrayHelper.HexStringToByteArray(privateKeyHex); - var signature = CryptoHelper.SignWithPrivateKey(privateKey, transactionData); - transaction.Signature = ByteString.CopyFrom(signature); - - return transaction; - } - - /// - /// Get the account address through the public key. - /// - /// - /// Account - public string GetAddressFromPubKey(string pubKey) - { - var publicKey = ByteArrayHelper.HexStringToByteArray(pubKey); - var address = Address.FromPublicKey(publicKey); - return address.GetFormatted(); - } - - /// - /// Get the account address through the private key. - /// - /// - /// - public string GetAddressFromPrivateKey(string privateKeyHex) - { - var address = Address.FromPublicKey(GetAElfKeyPair(privateKeyHex).PublicKey); - return address.GetFormatted(); - } - - public Address GetBase58String(string base58String) - { - return AddressHelper.Base58StringToAddress(base58String); - } - - #region private methods - - private ECKeyPair GetAElfKeyPair(string privateKeyHex) - { - var privateKey = ByteArrayHelper.HexStringToByteArray(privateKeyHex); - var keyPair = CryptoHelper.FromPrivateKey(privateKey); - - return keyPair; - } - - private string GetRequestUrl(string baseUrl, string relativeUrl) - { - return new Uri(new Uri(baseUrl + (baseUrl.EndsWith("/") ? "" : "/")), relativeUrl).ToString(); - } - - private void AssertValidAddress(params string[] addresses) - { - try - { - foreach (var address in addresses) - { - AddressHelper.Base58StringToAddress(address); - } - } - catch (Exception) - { - throw new AElfClientException(Error.Message[Error.InvalidAddress]); - } - } - - private void AssertValidHash(params string[] hashes) - { - try - { - foreach (var hash in hashes) - { - HashHelper.HexStringToHash(hash); - } - } - catch (Exception) - { - throw new AElfClientException(Error.Message[Error.InvalidBlockHash]); - } - } - - private void AssertValidTransactionId(params string[] transactionIds) - { - try - { - foreach (var transactionId in transactionIds) - { - HashHelper.HexStringToHash(transactionId); - } - } - catch (Exception) - { - throw new AElfClientException(Error.Message[Error.InvalidTransactionId]); - } - } - - #endregion - } -} \ No newline at end of file diff --git a/AElf.Client/Service/NetAppService.cs b/AElf.Client/Service/NetAppService.cs deleted file mode 100644 index f9e928c..0000000 --- a/AElf.Client/Service/NetAppService.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using AElf.Client.Dto; -using AElf.Client.Helper; - -namespace AElf.Client.Service -{ - public interface INetAppService - { - Task AddPeerAsync(string ipAddress); - - Task RemovePeerAsync(string ipAddress); - - Task> GetPeersAsync(bool withMetrics); - - Task GetNetworkInfoAsync(); - } - - public partial class AElfClient : INetAppService - { - /// - /// Attempt to add a node to the connected network nodes.Input parameter contains the ipAddress of the node. - /// - /// - /// Add successfully or not - public async Task AddPeerAsync(string ipAddress) - { - if (!EndpointHelper.TryParse(ipAddress, out var endpoint)) - { - return false; - } - - var url = GetRequestUrl(_baseUrl, "api/net/peer"); - var parameters = new Dictionary - { - {"address", endpoint.ToString()} - }; - - return await _httpService.PostResponseAsync(url, parameters); - } - - /// - /// Attempt to remove a node from the connected network nodes by given the ipAddress. - /// - /// - /// Delete successfully or not - public async Task RemovePeerAsync(string ipAddress) - { - if (!EndpointHelper.TryParse(ipAddress, out var endpoint)) - { - return false; - } - - var url = GetRequestUrl(_baseUrl, $"api/net/peer?address={endpoint}"); - return await _httpService.DeleteResponseAsObjectAsync(url); - } - - /// - /// Gets information about the peer nodes of the current node.Optional whether to include metrics. - /// - /// - /// Information about the peer nodes - public async Task> GetPeersAsync(bool withMetrics) - { - var url = GetRequestUrl(_baseUrl, $"api/net/peers?withMetrics={withMetrics}"); - return await _httpService.GetResponseAsync>(url); - } - - /// - /// Get the node's network information. - /// - /// Network information - public async Task GetNetworkInfoAsync() - { - var url = GetRequestUrl(_baseUrl, "api/net/networkInfo"); - return await _httpService.GetResponseAsync(url); - } - } -} \ No newline at end of file diff --git a/AElf.Client/Service/TransactionAppService.cs b/AElf.Client/Service/TransactionAppService.cs deleted file mode 100644 index ea8d60e..0000000 --- a/AElf.Client/Service/TransactionAppService.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using AElf.Client.Dto; - -namespace AElf.Client.Service -{ - public interface ITransactionAppService - { - Task GetTransactionPoolStatusAsync(); - - Task ExecuteTransactionAsync(ExecuteTransactionDto input); - - Task ExecuteRawTransactionAsync(ExecuteRawTransactionDto input); - - Task CreateRawTransactionAsync(CreateRawTransactionInput input); - - Task SendRawTransactionAsync(SendRawTransactionInput input); - - Task SendTransactionAsync(SendTransactionInput input); - - Task SendTransactionsAsync(SendTransactionsInput input); - - Task GetTransactionResultAsync(string transactionId); - - Task> GetTransactionResultsAsync(string blockHash, int offset = 0, - int limit = 10); - - Task GetMerklePathByTransactionIdAsync(string transactionId); - } - - public partial class AElfClient : ITransactionAppService - { - /// - /// Get information about the current transaction pool. - /// - /// TransactionPoolStatusOutput - public async Task GetTransactionPoolStatusAsync() - { - var url = GetRequestUrl(_baseUrl, "api/blockChain/transactionPoolStatus"); - return await _httpService.GetResponseAsync(url); - } - - /// - /// Call a read-only method of a contract. - /// - /// - /// - public async Task ExecuteTransactionAsync(ExecuteTransactionDto input) - { - var url = GetRequestUrl(_baseUrl, "api/blockChain/executeTransaction"); - var parameters = new Dictionary - { - {"RawTransaction", input.RawTransaction} - }; - - return await _httpService.PostResponseAsync(url, parameters); - } - - /// - /// Call a method of a contract by given serialized strings. - /// - /// - /// Serialized result - public async Task ExecuteRawTransactionAsync(ExecuteRawTransactionDto input) - { - var url = GetRequestUrl(_baseUrl, "api/blockChain/executeRawTransaction"); - var parameters = new Dictionary - { - {"RawTransaction", input.RawTransaction}, - {"Signature", input.Signature} - }; - - return await _httpService.PostResponseAsync(url, parameters); - } - - /// - /// Creates an unsigned serialized transaction. - /// - /// - /// CreateRawTransactionOutput - public async Task CreateRawTransactionAsync(CreateRawTransactionInput input) - { - var url = GetRequestUrl(_baseUrl, "api/blockChain/rawTransaction"); - var parameters = new Dictionary - { - {"From", input.From}, - {"To", input.To}, - {"RefBlockNumber", input.RefBlockNumber.ToString()}, - {"RefBlockHash", input.RefBlockHash}, - {"MethodName", input.MethodName}, - {"Params", input.Params} - }; - - return await _httpService.PostResponseAsync(url, parameters); - } - - /// - /// Broadcast a serialized transaction. - /// - /// - /// SendRawTransactionOutput - public async Task SendRawTransactionAsync(SendRawTransactionInput input) - { - var url = GetRequestUrl(_baseUrl, "api/blockChain/sendRawTransaction"); - var parameters = new Dictionary - { - {"Transaction", input.Transaction}, - {"Signature", input.Signature}, - {"ReturnTransaction", input.ReturnTransaction ? "true" : "false"} - }; - return await _httpService.PostResponseAsync(url, parameters); - } - - /// - /// Broadcast a transaction. - /// - /// - /// TransactionId - public async Task SendTransactionAsync(SendTransactionInput input) - { - var url = GetRequestUrl(_baseUrl, "api/blockChain/sendTransaction"); - var parameters = new Dictionary - { - {"RawTransaction", input.RawTransaction} - }; - return await _httpService.PostResponseAsync(url, parameters); - } - - /// - /// Broadcast volume transactions. - /// - /// - /// TransactionIds - public async Task SendTransactionsAsync(SendTransactionsInput input) - { - var url = GetRequestUrl(_baseUrl, "api/blockChain/sendTransactions"); - var parameters = new Dictionary - { - {"RawTransactions", input.RawTransactions} - }; - return await _httpService.PostResponseAsync(url, parameters); - } - - /// - /// Gets the result of transaction execution by the given transactionId. - /// - /// - /// TransactionResultDto - public async Task GetTransactionResultAsync(string transactionId) - { - AssertValidTransactionId(transactionId); - var url = GetRequestUrl(_baseUrl, $"api/blockChain/transactionResult?transactionId={transactionId}"); - return await _httpService.GetResponseAsync(url); - } - - /// - /// Get results of multiple transactions by specified blockHash and the offset. - /// - /// - /// - /// - /// TransactionResultDtos - public async Task> GetTransactionResultsAsync(string blockHash, int offset = 0, - int limit = 10) - { - AssertValidHash(blockHash); - var url = GetRequestUrl(_baseUrl, - $"api/blockChain/transactionResults?blockHash={blockHash}&offset={offset}&limit={limit}"); - return await _httpService.GetResponseAsync>(url); - } - - /// - /// Get merkle path of a transaction. - /// - /// - /// MerklePathDto - public async Task GetMerklePathByTransactionIdAsync(string transactionId) - { - AssertValidTransactionId(transactionId); - var url = GetRequestUrl(_baseUrl, $"api/blockChain/merklePathByTransactionId?transactionId={transactionId}"); - return await _httpService.GetResponseAsync(url); - } - } -} \ No newline at end of file diff --git a/all.sln b/all.sln new file mode 100644 index 0000000..fdc8295 --- /dev/null +++ b/all.sln @@ -0,0 +1,81 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{940361AC-2167-4D30-A4F6-9A543C608196}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{7CD2B508-C765-4720-B430-94E79135797A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client", "src\AElf.Client\AElf.Client.csproj", "{1AE7844D-B4D9-4F5A-9D25-7E551B61138E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Protobuf", "src\AElf.Client.Protobuf\AElf.Client.Protobuf.csproj", "{E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TokenManager", "examples\TokenManager\TokenManager.csproj", "{CA0B4594-2549-4DB1-9079-EA5FD739C6B6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionViewer", "examples\ElectionViewer\ElectionViewer.csproj", "{E678AABE-AF7B-45F4-B931-CF0D77C5AECA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AEDPoSViewer", "examples\AEDPoSViewer\AEDPoSViewer.csproj", "{BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Test", "test\AElf.Client.Test\AElf.Client.Test.csproj", "{4D019C99-8B1C-42B0-8630-F1E3661F414B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Abp", "src\AElf.Client.Abp\AElf.Client.Abp.csproj", "{BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.KeyStore", "src\AElf.KeyStore\AElf.KeyStore.csproj", "{74BABFFA-D040-4977-A45E-54385412C706}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.KeyStore.Tests", "test\AElf.KeyStore.Tests\AElf.KeyStore.Tests.csproj", "{1085F2A7-95F9-4941-AA7C-3CD1A5DAE016}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1AE7844D-B4D9-4F5A-9D25-7E551B61138E} = {940361AC-2167-4D30-A4F6-9A543C608196} + {E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB} = {940361AC-2167-4D30-A4F6-9A543C608196} + {CA0B4594-2549-4DB1-9079-EA5FD739C6B6} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8} + {E678AABE-AF7B-45F4-B931-CF0D77C5AECA} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8} + {BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8} + {4D019C99-8B1C-42B0-8630-F1E3661F414B} = {7CD2B508-C765-4720-B430-94E79135797A} + {BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F} = {940361AC-2167-4D30-A4F6-9A543C608196} + {74BABFFA-D040-4977-A45E-54385412C706} = {940361AC-2167-4D30-A4F6-9A543C608196} + {1085F2A7-95F9-4941-AA7C-3CD1A5DAE016} = {7CD2B508-C765-4720-B430-94E79135797A} + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Release|Any CPU.Build.0 = Release|Any CPU + {E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}.Release|Any CPU.Build.0 = Release|Any CPU + {CA0B4594-2549-4DB1-9079-EA5FD739C6B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA0B4594-2549-4DB1-9079-EA5FD739C6B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA0B4594-2549-4DB1-9079-EA5FD739C6B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA0B4594-2549-4DB1-9079-EA5FD739C6B6}.Release|Any CPU.Build.0 = Release|Any CPU + {E678AABE-AF7B-45F4-B931-CF0D77C5AECA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E678AABE-AF7B-45F4-B931-CF0D77C5AECA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E678AABE-AF7B-45F4-B931-CF0D77C5AECA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E678AABE-AF7B-45F4-B931-CF0D77C5AECA}.Release|Any CPU.Build.0 = Release|Any CPU + {BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}.Release|Any CPU.Build.0 = Release|Any CPU + {4D019C99-8B1C-42B0-8630-F1E3661F414B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D019C99-8B1C-42B0-8630-F1E3661F414B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D019C99-8B1C-42B0-8630-F1E3661F414B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D019C99-8B1C-42B0-8630-F1E3661F414B}.Release|Any CPU.Build.0 = Release|Any CPU + {BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}.Release|Any CPU.Build.0 = Release|Any CPU + {74BABFFA-D040-4977-A45E-54385412C706}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74BABFFA-D040-4977-A45E-54385412C706}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74BABFFA-D040-4977-A45E-54385412C706}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74BABFFA-D040-4977-A45E-54385412C706}.Release|Any CPU.Build.0 = Release|Any CPU + {1085F2A7-95F9-4941-AA7C-3CD1A5DAE016}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1085F2A7-95F9-4941-AA7C-3CD1A5DAE016}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1085F2A7-95F9-4941-AA7C-3CD1A5DAE016}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1085F2A7-95F9-4941-AA7C-3CD1A5DAE016}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..3bf6034 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,47 @@ +jobs: +- job: build_all_window + displayName: Build all tasks (window) + pool: + vmImage: 'windows-2019' + variables: + phpVersion: 7.2 + steps: + - task: UseDotNet@2 + displayName: 'Install .NET Core SDK' + inputs: + version: '6.0.x' + - powershell: ./scripts/aelf-node/start-window.ps1 + displayName: 'Build and Test' +# All tasks on Linux +- job: build_all_linux + displayName: Build all tasks (Linux) + services: + redis: + image: redis + ports: + - 6379:6379 + pool: + vmImage: ubuntu-latest + steps: + - task: UseDotNet@2 + inputs: + version: '6.0.x' + - script: cd scripts/aelf-node && bash start.sh + displayName: 'Deploy a full node' + - script: bash build.sh -target=test + displayName: 'build and test' +# All tasks on macOS +- job: build_all_macos + displayName: Build all tasks (macos) + pool: + vmImage: macos-latest + variables: + phpVersion: 7.2 + steps: + - task: UseDotNet@2 + inputs: + version: '6.0.x' + - script: cd scripts/aelf-node && bash start-mac.sh + displayName: 'Deploy a full node' + - script: bash build.sh -target=test + displayName: 'build and test' diff --git a/build.cake b/build.cake new file mode 100755 index 0000000..cca8919 --- /dev/null +++ b/build.cake @@ -0,0 +1,69 @@ +var target = Argument("target", "default"); +var rootPath = "./"; +var srcPath = rootPath + "AElf.Client/"; +var testPath = rootPath + "AElf.Client.Test/"; +var distPath = rootPath + "aelf-node/"; +var solution = rootPath + "all.sln"; +var srcProjects = GetFiles(srcPath + "AElf.Client.csproj"); + +Task("clean") + .Description("clean up project cache") + .Does(() => +{ + DeleteFiles(distPath + "*.nupkg"); + CleanDirectories(srcPath + "bin"); + CleanDirectories(srcPath + "obj"); + CleanDirectories(testPath + "bin"); + CleanDirectories(testPath + "obj"); +}); + +Task("restore") + .Description("restore project dependencies") + .Does(() => +{ + var restoreSettings = new DotNetCoreRestoreSettings{ + ArgumentCustomization = args => { + return args.Append("-v quiet");} +}; + DotNetCoreRestore(solution,restoreSettings); +}); + +Task("build") + .Description("Compilation project") + .IsDependentOn("clean") + .IsDependentOn("restore") + .Does(() => +{ + var buildSetting = new DotNetCoreBuildSettings{ + NoRestore = true, + Configuration = "Debug", + ArgumentCustomization = args => { + return args.Append("/clp:ErrorsOnly") + .Append("--no-incremental") + .Append("-v quiet");} + }; + + DotNetCoreBuild(solution, buildSetting); +}); +Task("test") + .Description("operation test") + .IsDependentOn("build") + .Does(() => +{ + var testSetting = new DotNetCoreTestSettings{ + NoRestore = true, + NoBuild = true +}; + var testProjects = GetFiles("./*.Test/*.csproj"); + + foreach(var testProject in testProjects) + { + DotNetCoreTest(testProject.FullPath, testSetting); + } +}); + +Task("default") + .Description("default run test(-target test)") + .IsDependentOn("build"); + +RunTarget(target); diff --git a/build.config b/build.config new file mode 100644 index 0000000..703c767 --- /dev/null +++ b/build.config @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +CAKE_VERSION=0.37.0 +DOTNET_VERSION=6.0.406 diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..e48d09a --- /dev/null +++ b/build.ps1 @@ -0,0 +1,154 @@ +#!/usr/bin/env pwsh +$DotNetInstallerUri = 'https://dot.net/v1/dotnet-install.ps1'; +$DotNetUnixInstallerUri = 'https://dot.net/v1/dotnet-install.sh' +$DotNetChannel = 'LTS' +$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent + +[string] $CakeVersion = '' +[string] $DotNetVersion= '' +foreach($line in Get-Content (Join-Path $PSScriptRoot 'build.config')) +{ + if ($line -like 'CAKE_VERSION=*') { + $CakeVersion = $line.SubString(13) + } + elseif ($line -like 'DOTNET_VERSION=*') { + $DotNetVersion =$line.SubString(15) + } +} + + +if ([string]::IsNullOrEmpty($CakeVersion) -or [string]::IsNullOrEmpty($DotNetVersion)) { + 'Failed to parse Cake / .NET Core SDK Version' + exit 1 +} + +# Make sure tools folder exists +$ToolPath = Join-Path $PSScriptRoot "tools" +if (!(Test-Path $ToolPath)) { + Write-Verbose "Creating tools directory..." + New-Item -Path $ToolPath -Type Directory -Force | out-null +} + + +if ($PSVersionTable.PSEdition -ne 'Core') { + # Attempt to set highest encryption available for SecurityProtocol. + # PowerShell will not set this by default (until maybe .NET 4.6.x). This + # will typically produce a message for PowerShell v2 (just an info + # message though) + try { + # Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48) + # Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't + # exist in .NET 4.0, even though they are addressable if .NET 4.5+ is + # installed (.NET 4.5 is an in-place upgrade). + [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48 + } catch { + Write-Output 'Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to upgrade to .NET Framework 4.5+ and PowerShell v3' + } +} + +########################################################################### +# INSTALL .NET CORE CLI +########################################################################### + +$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 +$env:DOTNET_CLI_TELEMETRY_OPTOUT=1 +$env:DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX=2 + + +Function Remove-PathVariable([string]$VariableToRemove) +{ + $SplitChar = ';' + if ($IsMacOS -or $IsLinux) { + $SplitChar = ':' + } + + $path = [Environment]::GetEnvironmentVariable("PATH", "User") + if ($path -ne $null) + { + $newItems = $path.Split($SplitChar, [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove } + [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join($SplitChar, $newItems), "User") + } + + $path = [Environment]::GetEnvironmentVariable("PATH", "Process") + if ($path -ne $null) + { + $newItems = $path.Split($SplitChar, [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove } + [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join($SplitChar, $newItems), "Process") + } +} + +# Get .NET Core CLI path if installed. +$FoundDotNetCliVersion = $null; +if (Get-Command dotnet -ErrorAction SilentlyContinue) { + $FoundDotNetCliVersion = dotnet --version; +} + +if($FoundDotNetCliVersion -ne $DotNetVersion) { + $InstallPath = Join-Path $PSScriptRoot ".dotnet" + if (!(Test-Path $InstallPath)) { + New-Item -Path $InstallPath -ItemType Directory -Force | Out-Null; + } + + if ($IsMacOS -or $IsLinux) { + $ScriptPath = Join-Path $InstallPath 'dotnet-install.sh' + (New-Object System.Net.WebClient).DownloadFile($DotNetUnixInstallerUri, $ScriptPath); + & bash $ScriptPath --version "$DotNetVersion" --install-dir "$InstallPath" --channel "$DotNetChannel" --no-path + + Remove-PathVariable "$InstallPath" + $env:PATH = "$($InstallPath):$env:PATH" + } + else { + $ScriptPath = Join-Path $InstallPath 'dotnet-install.ps1' + (New-Object System.Net.WebClient).DownloadFile($DotNetInstallerUri, $ScriptPath); + & $ScriptPath -Channel $DotNetChannel -Version $DotNetVersion -InstallDir $InstallPath; + + Remove-PathVariable "$InstallPath" + $env:PATH = "$InstallPath;$env:PATH" + } + $env:DOTNET_ROOT=$InstallPath +} + +########################################################################### +# INSTALL CAKE +########################################################################### + +# Make sure Cake has been installed. +[string] $CakeExePath = '' +[string] $CakeInstalledVersion = Get-Command dotnet-cake -ErrorAction SilentlyContinue | % {&$_.Source --version} + +if ($CakeInstalledVersion -eq $CakeVersion) { + # Cake found locally + $CakeExePath = (Get-Command dotnet-cake).Source +} +else { + $CakePath = [System.IO.Path]::Combine($ToolPath,'.store', 'cake.tool', $CakeVersion) # Old PowerShell versions Join-Path only supports one child path + + $CakeExePath = (Get-ChildItem -Path $ToolPath -Filter "dotnet-cake*" -File| ForEach-Object FullName | Select-Object -First 1) + + + if ((!(Test-Path -Path $CakePath -PathType Container)) -or (!(Test-Path $CakeExePath -PathType Leaf))) { + + if ((![string]::IsNullOrEmpty($CakeExePath)) -and (Test-Path $CakeExePath -PathType Leaf)) + { + & dotnet tool uninstall --tool-path $ToolPath Cake.Tool + } + + & dotnet tool install --tool-path $ToolPath --version $CakeVersion Cake.Tool + if ($LASTEXITCODE -ne 0) + { + 'Failed to install cake' + exit 1 + } + $CakeExePath = (Get-ChildItem -Path $ToolPath -Filter "dotnet-cake*" -File| ForEach-Object FullName | Select-Object -First 1) + } +} + +########################################################################### +# RUN BUILD SCRIPT +########################################################################### +& "$CakeExePath" ./build.cake --bootstrap +if ($LASTEXITCODE -eq 0) +{ + & "$CakeExePath" ./build.cake $args +} +exit $LASTEXITCODE \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..06bcee8 --- /dev/null +++ b/build.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Define varibles +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +source $SCRIPT_DIR/build.config +TOOLS_DIR=$SCRIPT_DIR/tools +CAKE_EXE=$TOOLS_DIR/dotnet-cake +CAKE_PATH=$TOOLS_DIR/.store/cake.tool/$CAKE_VERSION + +if [ "$CAKE_VERSION" = "" ] || [ "$DOTNET_VERSION" = "" ]; then + echo "An error occured while parsing Cake / .NET Core SDK version." + exit 1 +fi + +# Make sure the tools folder exist. +if [ ! -d "$TOOLS_DIR" ]; then + mkdir "$TOOLS_DIR" +fi + +########################################################################### +# INSTALL .NET CORE CLI +########################################################################### + +export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +export DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0 +export DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX=2 + +DOTNET_INSTALLED_VERSION=$(dotnet --version 2>&1) + +if [ "$DOTNET_VERSION" != "$DOTNET_INSTALLED_VERSION" ]; then + echo "Installing .NET CLI..." + if [ ! -d "$SCRIPT_DIR/.dotnet" ]; then + mkdir "$SCRIPT_DIR/.dotnet" + fi + curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" https://dot.net/v1/dotnet-install.sh + bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --version $DOTNET_VERSION --install-dir .dotnet --no-path + export PATH="$SCRIPT_DIR/.dotnet":$PATH + export DOTNET_ROOT="$SCRIPT_DIR/.dotnet" +fi + +########################################################################### +# INSTALL CAKE +########################################################################### + +CAKE_INSTALLED_VERSION=$(dotnet-cake --version 2>&1) + +if [ "$CAKE_VERSION" != "$CAKE_INSTALLED_VERSION" ]; then + if [ ! -f "$CAKE_EXE" ] || [ ! -d "$CAKE_PATH" ]; then + if [ -f "$CAKE_EXE" ]; then + dotnet tool uninstall --tool-path $TOOLS_DIR Cake.Tool + fi + + echo "Installing Cake $CAKE_VERSION..." + dotnet tool install --tool-path $TOOLS_DIR --version $CAKE_VERSION Cake.Tool + if [ $? -ne 0 ]; then + echo "An error occured while installing Cake." + exit 1 + fi + fi + + # Make sure that Cake has been installed. + if [ ! -f "$CAKE_EXE" ]; then + echo "Could not find Cake.exe at '$CAKE_EXE'." + exit 1 + fi +else + CAKE_EXE="dotnet-cake" +fi + +########################################################################### +# RUN BUILD SCRIPT +########################################################################### + +# Start Cake +(exec "$CAKE_EXE" build.cake --bootstrap) && (exec "$CAKE_EXE" build.cake "$@") \ No newline at end of file diff --git a/examples/AEDPoSViewer/AEDPoSViewer.csproj b/examples/AEDPoSViewer/AEDPoSViewer.csproj new file mode 100644 index 0000000..a356a80 --- /dev/null +++ b/examples/AEDPoSViewer/AEDPoSViewer.csproj @@ -0,0 +1,30 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + + + + + + + + PreserveNewest + Always + + + + diff --git a/examples/AEDPoSViewer/AEDPoSViewerConstants.cs b/examples/AEDPoSViewer/AEDPoSViewerConstants.cs new file mode 100644 index 0000000..14e98e2 --- /dev/null +++ b/examples/AEDPoSViewer/AEDPoSViewerConstants.cs @@ -0,0 +1,6 @@ +namespace AEDPoSViewer; + +public class AEDPoSViewerConstants +{ + public const string ConsensusSmartContractName = "AElf.ContractNames.Consensus"; +} \ No newline at end of file diff --git a/examples/AEDPoSViewer/AEDPoSViewerHostedService.cs b/examples/AEDPoSViewer/AEDPoSViewerHostedService.cs new file mode 100644 index 0000000..bdb0b9c --- /dev/null +++ b/examples/AEDPoSViewer/AEDPoSViewerHostedService.cs @@ -0,0 +1,45 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; +using Volo.Abp; + +namespace AEDPoSViewer; + +public class AEDPoSViewerHostedService : IHostedService +{ + private IAbpApplicationWithInternalServiceProvider _abpApplication; + + private readonly IConfiguration _configuration; + private readonly IHostEnvironment _hostEnvironment; + + public AEDPoSViewerHostedService(IConfiguration configuration, IHostEnvironment hostEnvironment) + { + _configuration = configuration; + _hostEnvironment = hostEnvironment; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + _abpApplication = await AbpApplicationFactory.CreateAsync(options => + { + options.Services.ReplaceConfiguration(_configuration); + options.Services.AddSingleton(_hostEnvironment); + + options.UseAutofac(); + options.Services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog()); + }); + + await _abpApplication.InitializeAsync(); + + var helloWorldService = _abpApplication.ServiceProvider.GetRequiredService(); + await helloWorldService.RunAsync(); + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + await _abpApplication.ShutdownAsync(); + } +} \ No newline at end of file diff --git a/examples/AEDPoSViewer/AEDPoSViewerModule.cs b/examples/AEDPoSViewer/AEDPoSViewerModule.cs new file mode 100644 index 0000000..1bd743a --- /dev/null +++ b/examples/AEDPoSViewer/AEDPoSViewerModule.cs @@ -0,0 +1,12 @@ +using AElf.Client.Abp; +using Volo.Abp.Modularity; + +namespace AEDPoSViewer; + +[DependsOn( + typeof(AElfClientModule) + )] +public class AEDPoSViewerModule : AbpModule +{ + +} \ No newline at end of file diff --git a/examples/AEDPoSViewer/AEDPoSViewerService.cs b/examples/AEDPoSViewer/AEDPoSViewerService.cs new file mode 100644 index 0000000..6dafa91 --- /dev/null +++ b/examples/AEDPoSViewer/AEDPoSViewerService.cs @@ -0,0 +1,38 @@ +using AElf.Client; +using AElf.Contracts.Consensus.AEDPoS; +using Google.Protobuf; +using Google.Protobuf.WellKnownTypes; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.DependencyInjection; + +namespace AEDPoSViewer; + +public class AEDPoSViewerService : ITransientDependency +{ + private IServiceScopeFactory ServiceScopeFactory { get; } + + public ILogger Logger { get; set; } + + public AEDPoSViewerService(IServiceScopeFactory serviceScopeFactory) + { + ServiceScopeFactory = serviceScopeFactory; + + Logger = NullLogger.Instance; + } + + public async Task RunAsync() + { + using var scope = ServiceScopeFactory.CreateScope(); + + var clientService = scope.ServiceProvider.GetRequiredService(); + + var result = await clientService.ViewSystemAsync(AEDPoSViewerConstants.ConsensusSmartContractName, + "GetCurrentRoundInformation", new Empty(), EndpointType.MainNetSidechain.ToString(), "Ean"); + + var round = new Round(); + round.MergeFrom(result); + Logger.LogInformation($"Current round: {round}"); + } +} \ No newline at end of file diff --git a/examples/AEDPoSViewer/Program.cs b/examples/AEDPoSViewer/Program.cs new file mode 100644 index 0000000..badd66f --- /dev/null +++ b/examples/AEDPoSViewer/Program.cs @@ -0,0 +1,40 @@ +using AEDPoSViewer; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; +using Serilog.Events; + +Log.Logger = new LoggerConfiguration() + .MinimumLevel.Information() + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("Volo.Abp", LogEventLevel.Warning) +#if DEBUG + .MinimumLevel.Override("AEDPoSViewer", LogEventLevel.Debug) +#else + .MinimumLevel.Override("AEDPoSViewer", LogEventLevel.Information) +#endif + .Enrich.FromLogContext() + .WriteTo.Async(c => c.File($"Logs/aelf-consensus-viewer-{DateTime.UtcNow:yyyy-MM-dd}.logs")) + .WriteTo.Async(c => c.Console()) + .CreateLogger(); + +try +{ + await Host.CreateDefaultBuilder(args) + .ConfigureServices(services => + { + services.AddHostedService(); + }) + .UseSerilog() + .RunConsoleAsync(); + return 0; +} +catch (Exception ex) +{ + Log.Fatal(ex, "Host terminated unexpectedly!"); + return 1; +} +finally +{ + Log.CloseAndFlush(); +} \ No newline at end of file diff --git a/examples/AEDPoSViewer/appsettings.json b/examples/AEDPoSViewer/appsettings.json new file mode 100644 index 0000000..ec1136b --- /dev/null +++ b/examples/AEDPoSViewer/appsettings.json @@ -0,0 +1,40 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "AElfClient": { + "ClientConfigList": [ + { + "Alias": "Example", + "Endpoint": "http://192.168.0.31:6800", + "UserName": "", + "Password": "", + "Timeout": 100 + } + ] + }, + "AElfAccount":{ + "KeyDirectory": "", + "AccountConfigList": [ + { + "Alias": "Ean", + "PrivateKey": "8cc296e44d9e8881942e75a21ebc116ed3f29e39e0eaace1c92dc21e86d215c3", + "Address": "2AiXjNszZwUMdonm2RYb3GsB3aLUU3hkD1fxoazMwqPAamerLQ", + "Password": "aelftest" + }, + { + "Alias": "Test1", + "Address": "215tht8WyakoxNK4SvsR132jChydxE27RtJN8HSk1UXxuDQnmM", + "Password": "aelftest" + }, + { + "Alias": "Test2", + "PrivateKey": "5e2f12d13e4527ad1128e07db00f1614ec6b8b51662e68d4fdb42125ab384195", + } + ] + } +} \ No newline at end of file diff --git a/examples/ElectionViewer/ElectionViewer.csproj b/examples/ElectionViewer/ElectionViewer.csproj new file mode 100644 index 0000000..b9de063 --- /dev/null +++ b/examples/ElectionViewer/ElectionViewer.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/examples/ElectionViewer/Program.cs b/examples/ElectionViewer/Program.cs new file mode 100644 index 0000000..e5dff12 --- /dev/null +++ b/examples/ElectionViewer/Program.cs @@ -0,0 +1,3 @@ +// See https://aka.ms/new-console-template for more information + +Console.WriteLine("Hello, World!"); \ No newline at end of file diff --git a/examples/TokenManager/Program.cs b/examples/TokenManager/Program.cs new file mode 100644 index 0000000..e5dff12 --- /dev/null +++ b/examples/TokenManager/Program.cs @@ -0,0 +1,3 @@ +// See https://aka.ms/new-console-template for more information + +Console.WriteLine("Hello, World!"); \ No newline at end of file diff --git a/examples/TokenManager/TokenManager.csproj b/examples/TokenManager/TokenManager.csproj new file mode 100644 index 0000000..b9de063 --- /dev/null +++ b/examples/TokenManager/TokenManager.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/scripts/aelf-node/appsettings.MainChain.TestNet.json b/scripts/aelf-node/appsettings.MainChain.TestNet.json new file mode 100644 index 0000000..e97f765 --- /dev/null +++ b/scripts/aelf-node/appsettings.MainChain.TestNet.json @@ -0,0 +1,13 @@ +{ +"ChainId": "AELF", + "Economic": { + "Symbol": "ELF", + "TokenName": "elf token", + "TotalSupply": 100000000000000000, + "Decimals": 8, + "IsBurnable": true, + "DividendPoolRatio": 0.12, + "MinimumLockTime": 7776000, + "MaximumLockTime": 93312000 + } +} diff --git a/scripts/aelf-node/appsettings.json b/scripts/aelf-node/appsettings.json new file mode 100644 index 0000000..082d14e --- /dev/null +++ b/scripts/aelf-node/appsettings.json @@ -0,0 +1,44 @@ +{ + "ChainId": "AELF", + "ChainType": "MainChain", + "NetType": "TestNet", + "AllowedHosts": "*", + "CorsOrigins": "*", + "ConnectionStrings": { + "BlockchainDb": "redis://127.0.0.1:6379", + "StateDb": "redis://127.0.0.1:6379" + }, + "Account": { + "NodeAccount": "SD6BXDrKT2syNd1WehtPyRo3dPBiXqfGUj8UJym7YP9W9RynM", + "NodeAccountPassword": "123" + }, + "Network": { + "BootNodes": [ + ], + "ListeningPort": 6800, + "NetAllowed": "", + "NetWhitelist": [] + }, + "Kestrel": { + "Endpoints": { + "Http": { + "Url": "http://*:8001/" + } + } + }, + "Runner": { + "BlackList": [], + "WhiteList": [] + }, + "Consensus": { + "InitialMinerList": [ + ], + "MiningInterval": 4000, + "StartTimestamp": "0", + "PeriodSeconds": 604800, + "MinerIncreaseInterval": 31536000 + }, + "Transaction": { + "PoolLimit": 10240 + } +} diff --git a/scripts/aelf-node/keys/SD6BXDrKT2syNd1WehtPyRo3dPBiXqfGUj8UJym7YP9W9RynM.json b/scripts/aelf-node/keys/SD6BXDrKT2syNd1WehtPyRo3dPBiXqfGUj8UJym7YP9W9RynM.json new file mode 100644 index 0000000..82dbef8 --- /dev/null +++ b/scripts/aelf-node/keys/SD6BXDrKT2syNd1WehtPyRo3dPBiXqfGUj8UJym7YP9W9RynM.json @@ -0,0 +1 @@ +{"crypto":{"cipher":"aes-128-ctr","ciphertext":"6bed2f92088d090861e38f909047d2b68d1b3d1ec1913781916d12ae336bde59","cipherparams":{"iv":"9ac23ad68f7b0f34d1541a062b02693f"},"kdf":"scrypt","mac":"0b5b0b3b50d52c0061742077a47b6600008b3fc6c1a00c75095d07f07f3571cf","kdfparams":{"n":262144,"r":1,"p":8,"dklen":32,"salt":"4b27b913bb54a1cfe5195fb8bddcff3b5afc26a6f3fb387adb3bf0c63e7eed48"}},"id":"ee802828-4993-4b6f-b47c-fdba2100767f","address":"SD6BXDrKT2syNd1WehtPyRo3dPBiXqfGUj8UJym7YP9W9RynM","version":3} \ No newline at end of file diff --git a/scripts/aelf-node/start-mac.sh b/scripts/aelf-node/start-mac.sh new file mode 100644 index 0000000..7d6d2b1 --- /dev/null +++ b/scripts/aelf-node/start-mac.sh @@ -0,0 +1,10 @@ +brew install redis +brew services start redis +brew install unzip +mkdir -p ~/.local/share/aelf/keys +cd ../../ +wget https://github.com/AElfProject/AElf/releases/download/v1.2.3/aelf.zip && unzip aelf.zip +cp scripts/aelf-node/keys/SD6BXDrKT2syNd1WehtPyRo3dPBiXqfGUj8UJym7YP9W9RynM.json ~/.local/share/aelf/keys/ +cp scripts/aelf-node/app* aelf/ +echo "start node" +cd aelf && dotnet AElf.Launcher.dll >/dev/null 2>&1 & diff --git a/scripts/aelf-node/start-window.ps1 b/scripts/aelf-node/start-window.ps1 new file mode 100644 index 0000000..7397a99 --- /dev/null +++ b/scripts/aelf-node/start-window.ps1 @@ -0,0 +1,15 @@ +wget https://github.com/microsoftarchive/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.zip -OutFile redis.zip +Expand-Archive -Path redis.zip -DestinationPath redis ; +$job1 = Start-Job -ScriptBlock { cd D:\a\1\s\redis; .\redis-server.exe; } +sleep 30 +mkdir -p C:\Users\VssAdministrator\AppData\Local\aelf\keys +cp -r scripts\aelf-node\keys\* C:\Users\VssAdministrator\AppData\Local\aelf\keys; +wget https://github.com/AElfProject/AElf/releases/download/v1.2.3/aelf.zip -OutFile aelf.zip ; +Expand-Archive -Path aelf.zip -DestinationPath aelf ; +cp scripts\aelf-node\appsettings.json aelf\aelf\appsettings.json ; +cp scripts\aelf-node\appsettings.MainChain.TestNet.json aelf\aelf\appsettings.MainChain.TestNet.json ; +cd aelf/aelf +$job2 = Start-Job -ScriptBlock { cd D:\a\1\s\aelf\aelf; dotnet AElf.Launcher.dll; } +sleep 60 +cd D:\a\1\s +PowerShell.exe -file build.ps1 --target=test diff --git a/scripts/aelf-node/start.sh b/scripts/aelf-node/start.sh new file mode 100644 index 0000000..d00e82f --- /dev/null +++ b/scripts/aelf-node/start.sh @@ -0,0 +1,16 @@ +#!/bin/bash +ip=`ip a | grep eth0 |grep 'inet' | awk -F/ '{print $1}'| awk '{print $2}'` +sudo apt update && apt install unzip +sudo mkdir -p /home/ubuntu/.ssh/aelf/keys && sudo mkdir -p /root/.ssh/aelf/keys +cd ../../ +wget https://github.com/AElfProject/AElf/releases/download/v1.2.3/aelf.zip +sudo unzip aelf.zip +sed -i "s/127.0.0.1/$ip/g" scripts/aelf-node/appsettings.json +sudo mkdir -p aelf/aelf/keys +sudo cp scripts/aelf-node/keys/*.json aelf/aelf/keys/ +sudo cp scripts/aelf-node/app* aelf/ +echo "start node" +cd aelf && sudo dotnet AElf.Launcher.dll >/dev/null 2>&1 & +sleep 30 +height=`curl -s http://$ip:8001/api/blockChain/blockHeight` +echo "height is $height" diff --git a/src/AElf.Client.Abp/AElf.Client.Abp.csproj b/src/AElf.Client.Abp/AElf.Client.Abp.csproj new file mode 100644 index 0000000..2f6815f --- /dev/null +++ b/src/AElf.Client.Abp/AElf.Client.Abp.csproj @@ -0,0 +1,21 @@ + + + + net6.0 + enable + enable + AElf.Client.Abp + C# sdk with abp module. + AElf + true + + + + + + + + + + + diff --git a/src/AElf.Client.Abp/AElfClientModule.cs b/src/AElf.Client.Abp/AElfClientModule.cs new file mode 100644 index 0000000..95cfe53 --- /dev/null +++ b/src/AElf.Client.Abp/AElfClientModule.cs @@ -0,0 +1,20 @@ +using AElf.Client.Options; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace AElf.Client.Abp; + +[DependsOn( + typeof(AbpAutofacModule) + )] +public class AElfClientModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + Configure(options => { configuration.GetSection("AElfClient").Bind(options); }); + Configure(options => { configuration.GetSection("AElfAccount").Bind(options); }); + } +} \ No newline at end of file diff --git a/src/AElf.Client.Abp/AElfClientService.cs b/src/AElf.Client.Abp/AElfClientService.cs new file mode 100644 index 0000000..734cbb7 --- /dev/null +++ b/src/AElf.Client.Abp/AElfClientService.cs @@ -0,0 +1,54 @@ +using AElf.Client.Dto; +using Google.Protobuf; +using Volo.Abp.DependencyInjection; + +namespace AElf.Client.Abp; + +public class AElfClientService : IAElfClientService, ITransientDependency +{ + private readonly IAElfClientProvider _aelfClientProvider; + private readonly IAElfAccountProvider _aelfAccountProvider; + + public AElfClientService(IAElfClientProvider aelfClientProvider, IAElfAccountProvider aelfAccountProvider) + { + _aelfClientProvider = aelfClientProvider; + _aelfAccountProvider = aelfAccountProvider; + } + + public async Task ViewAsync(string contractAddress, string methodName, IMessage parameter, string clientAlias, + string accountAlias = "Default") + { + var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias); + var aelfAccount = _aelfAccountProvider.GetPrivateKey(alias: accountAlias); + var tx = new TransactionBuilder(aelfClient) + .UsePrivateKey(aelfAccount) + .UseContract(contractAddress) + .UseMethod(methodName) + .UseParameter(parameter) + .Build(); + return await PerformViewAsync(aelfClient, tx); + } + + public async Task ViewSystemAsync(string systemContractName, string methodName, IMessage parameter, string clientAlias, + string accountAlias = "Default") + { + var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias); + var privateKey = _aelfAccountProvider.GetPrivateKey(alias: accountAlias); + var tx = new TransactionBuilder(aelfClient) + .UsePrivateKey(privateKey) + .UseSystemContract(systemContractName) + .UseMethod(methodName) + .UseParameter(parameter) + .Build(); + return await PerformViewAsync(aelfClient, tx); + } + + private async Task PerformViewAsync(AElfClient aelfClient, Transaction tx) + { + var result = await aelfClient.ExecuteTransactionAsync(new ExecuteTransactionDto + { + RawTransaction = tx.ToByteArray().ToHex() + }); + return ByteArrayHelper.HexStringToByteArray(result); + } +} \ No newline at end of file diff --git a/src/AElf.Client.Abp/GlobalUsings.cs b/src/AElf.Client.Abp/GlobalUsings.cs new file mode 100644 index 0000000..e2e7f5c --- /dev/null +++ b/src/AElf.Client.Abp/GlobalUsings.cs @@ -0,0 +1 @@ +global using AElf.Types; \ No newline at end of file diff --git a/src/AElf.Client.Abp/IAElfAccountProvider.cs b/src/AElf.Client.Abp/IAElfAccountProvider.cs new file mode 100644 index 0000000..f3a1809 --- /dev/null +++ b/src/AElf.Client.Abp/IAElfAccountProvider.cs @@ -0,0 +1,98 @@ +using AElf.Client.Abp.Infrastructure; +using AElf.Client.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Nethereum.KeyStore; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace AElf.Client.Abp; + +public interface IAElfAccountProvider +{ + byte[] GetPrivateKey(string? alias = null, string? address = null); + void SetPrivateKey(byte[] privateKey, string? alias = null, string? address = null); +} + +public class AElfAccountProvider : Dictionary, IAElfAccountProvider, ISingletonDependency +{ + private readonly IKeyDirectoryProvider _keyDirectoryProvider; + + public ILogger Logger { get; set; } + + public AElfAccountProvider(IKeyDirectoryProvider keyDirectoryProvider, + IOptionsSnapshot aelfAccountOptions) + { + Logger = NullLogger.Instance; + _keyDirectoryProvider = keyDirectoryProvider; + var defaultPrivateKey = ByteArrayHelper.HexStringToByteArray(AElfClientConstants.DefaultPrivateKey); + SetPrivateKey(defaultPrivateKey, "Default", Address.FromPublicKey(defaultPrivateKey).ToBase58()); + + var keyStoreService = new KeyStoreService(); + + foreach (var accountConfig in aelfAccountOptions.Value.AccountConfigList) + { + if (string.IsNullOrWhiteSpace(accountConfig.PrivateKey)) + { + var keyFilePath = GetKeyFileFullPath(accountConfig.Address, aelfAccountOptions.Value.KeyDirectory); + var privateKey = AsyncHelper.RunSync(() => Task.Run(() => + { + using var textReader = File.OpenText(keyFilePath); + var json = textReader.ReadToEnd(); + return keyStoreService.DecryptKeyStoreFromJson(accountConfig.Password, json); + })); + SetPrivateKey(privateKey, accountConfig.Alias, accountConfig.Address); + } + else + { + var privateKey = ByteArrayHelper.HexStringToByteArray(accountConfig.PrivateKey); + SetPrivateKey(privateKey, accountConfig.Alias, Address.FromPublicKey(privateKey).ToBase58()); + } + } + } + + public byte[] GetPrivateKey(string? alias = null, string? address = null) + { + var keys = Keys + .WhereIf(!alias.IsNullOrWhiteSpace(), a => a.Alias == alias) + .WhereIf(!address.IsNullOrWhiteSpace(), a => a.Address == address) + .ToList(); + if (keys.Count != 1) + { + throw new AElfClientException($"Failed to get private key of {alias} - {address}."); + } + + return this[keys.Single()]; + } + + public void SetPrivateKey(byte[] privateKey, string? alias = null, string? address = null) + { + TryAdd(new AElfAccountInfo + { + Alias = alias, + Address = address + }, privateKey); + } + + private string GetKeyFileFullPath(string address, string configuredKeyDirectory) + { + var dirPath = GetKeystoreDirectoryPath(configuredKeyDirectory); + var filePath = Path.Combine(dirPath, address); + var filePathWithExtension = Path.ChangeExtension(filePath, ".json"); + return filePathWithExtension; + } + + private string GetKeystoreDirectoryPath(string? configuredKeyDirectory) + { + return string.IsNullOrWhiteSpace(configuredKeyDirectory) + ? Path.Combine(_keyDirectoryProvider.GetAppDataPath(), "keys") + : configuredKeyDirectory; + } +} + +public class AElfAccountInfo +{ + public string? Alias { get; set; } + public string? Address { get; set; } +} \ No newline at end of file diff --git a/src/AElf.Client.Abp/IAElfClientProvider.cs b/src/AElf.Client.Abp/IAElfClientProvider.cs new file mode 100644 index 0000000..d138778 --- /dev/null +++ b/src/AElf.Client.Abp/IAElfClientProvider.cs @@ -0,0 +1,79 @@ +using AElf.Client.Options; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace AElf.Client; + +public interface IAElfClientProvider +{ + AElfClient GetClient(string? alias = null, string? environment = null, int? chainId = null, string? chainType = null); + + void SetClient(AElfClient client, string? environment = null, int? chainId = null, string? chainType = null, + string? alias = null); +} + +public class AElfClientProvider : Dictionary, IAElfClientProvider, ISingletonDependency +{ + public AElfClientProvider(IOptionsSnapshot aelfClientOptions) + { + var clientBuilder = new AElfClientBuilder(); + SetClient(clientBuilder.UsePublicEndpoint(EndpointType.MainNetMainChain).Build(), "MainNet", + AElfClientConstants.MainChainId, "MainChain", EndpointType.MainNetMainChain.ToString()); + SetClient(clientBuilder.UsePublicEndpoint(EndpointType.MainNetSidechain).Build(), "MainNet", + AElfClientConstants.SidechainId, "Sidechain", EndpointType.MainNetSidechain.ToString()); + SetClient(clientBuilder.UsePublicEndpoint(EndpointType.TestNetMainChain).Build(), "TestNet", + AElfClientConstants.MainChainId, "MainChain", EndpointType.TestNetMainChain.ToString()); + SetClient(clientBuilder.UsePublicEndpoint(EndpointType.TestNetSidechain).Build(), "MainNet", + AElfClientConstants.SidechainId, "Sidechain", EndpointType.TestNetSidechain.ToString()); + SetClient(clientBuilder.UsePublicEndpoint(EndpointType.Local).Build(), "Local", AElfClientConstants.MainChainId, + "MainChain", EndpointType.Local.ToString()); + + foreach (var clientConfig in aelfClientOptions.Value.ClientConfigList) + { + var client = clientBuilder + .UseEndpoint(clientConfig.Endpoint) + .ManagePeerInfo(clientConfig.UserName, clientConfig.Password) + .SetHttpTimeout(clientConfig.Timeout) + .Build(); + SetClient(client, alias: clientConfig.Alias); + } + } + + public AElfClient GetClient(string? alias = null, string? environment = null, int? chainId = null, + string? chainType = null) + { + var keys = Keys + .WhereIf(!alias.IsNullOrWhiteSpace(), c => c.Alias == alias) + .WhereIf(!environment.IsNullOrWhiteSpace(), c => c.Environment == environment) + .WhereIf(chainId.HasValue, c => c.ChainId == chainId) + .WhereIf(!chainType.IsNullOrWhiteSpace(), c => c.ChainType == chainType) + .ToList(); + if (keys.Count != 1) + { + throw new AElfClientException( + $"Failed to get client of {alias} - {environment} - {chainId} - {chainType}."); + } + + return this[keys.Single()]; + } + + public void SetClient(AElfClient client, string? environment = null, int? chainId = null, string? chainType = null, + string? alias = null) + { + TryAdd(new AElfClientInfo + { + Environment = environment, + ChainId = chainId, + ChainType = chainType, + Alias = alias + }, client); + } +} + +public class AElfClientInfo +{ + public string? Environment { get; set; } + public int? ChainId { get; set; } + public string? ChainType { get; set; } + public string? Alias { get; set; } +} \ No newline at end of file diff --git a/src/AElf.Client.Abp/IAElfClientService.cs b/src/AElf.Client.Abp/IAElfClientService.cs new file mode 100644 index 0000000..3d126f5 --- /dev/null +++ b/src/AElf.Client.Abp/IAElfClientService.cs @@ -0,0 +1,12 @@ +using Google.Protobuf; + +namespace AElf.Client; + +public interface IAElfClientService +{ + Task ViewAsync(string contractAddress, string methodName, IMessage parameter, string clientAlias, + string accountAlias = "Default"); + + Task ViewSystemAsync(string systemContractName, string methodName, IMessage parameter, + string clientAlias, string accountAlias = "Default"); +} \ No newline at end of file diff --git a/src/AElf.Client.Abp/Infrastructure/IKeyDirectoryProvider.cs b/src/AElf.Client.Abp/Infrastructure/IKeyDirectoryProvider.cs new file mode 100644 index 0000000..a89a5ee --- /dev/null +++ b/src/AElf.Client.Abp/Infrastructure/IKeyDirectoryProvider.cs @@ -0,0 +1,6 @@ +namespace AElf.Client.Abp.Infrastructure; + +public interface IKeyDirectoryProvider +{ + string GetAppDataPath(); +} \ No newline at end of file diff --git a/src/AElf.Client.Abp/Infrastructure/KeyDirectoryProvider.cs b/src/AElf.Client.Abp/Infrastructure/KeyDirectoryProvider.cs new file mode 100644 index 0000000..99dd09b --- /dev/null +++ b/src/AElf.Client.Abp/Infrastructure/KeyDirectoryProvider.cs @@ -0,0 +1,24 @@ +using Volo.Abp.DependencyInjection; + +namespace AElf.Client.Abp.Infrastructure; + +public class KeyDirectoryProvider : IKeyDirectoryProvider, ISingletonDependency +{ + private const string ApplicationFolderName = "aelf"; + private string _appDataPath; + + public string GetAppDataPath() + { + if (string.IsNullOrWhiteSpace(_appDataPath)) + { + _appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ApplicationFolderName); + + if (!Directory.Exists(_appDataPath)) + { + Directory.CreateDirectory(_appDataPath); + } + } + + return _appDataPath; + } +} \ No newline at end of file diff --git a/src/AElf.Client.Abp/Options/AElfAccountOptions.cs b/src/AElf.Client.Abp/Options/AElfAccountOptions.cs new file mode 100644 index 0000000..310f2f5 --- /dev/null +++ b/src/AElf.Client.Abp/Options/AElfAccountOptions.cs @@ -0,0 +1,15 @@ +namespace AElf.Client.Options; + +public class AElfAccountOptions +{ + public string KeyDirectory { get; set; } + public List AccountConfigList { get; set; } = new(); +} + +public class AccountConfig +{ + public string Alias { get; set; } + public string Address { get; set; } + public string Password { get; set; } + public string PrivateKey { get; set; } +} \ No newline at end of file diff --git a/src/AElf.Client.Abp/Options/AElfClientOptions.cs b/src/AElf.Client.Abp/Options/AElfClientOptions.cs new file mode 100644 index 0000000..1caf518 --- /dev/null +++ b/src/AElf.Client.Abp/Options/AElfClientOptions.cs @@ -0,0 +1,15 @@ +namespace AElf.Client.Options; + +public class AElfClientOptions +{ + public List ClientConfigList { get; set; } = new(); +} + +public class ClientConfig +{ + public string Alias { get; set; } + public string Endpoint { get; set; } + public string UserName { get; set; } + public string Password { get; set; } + public int Timeout { get; set; } = 60; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/AElf.Client.Protobuf.csproj b/src/AElf.Client.Protobuf/AElf.Client.Protobuf.csproj new file mode 100644 index 0000000..59576ca --- /dev/null +++ b/src/AElf.Client.Protobuf/AElf.Client.Protobuf.csproj @@ -0,0 +1,45 @@ + + + + netstandard2.1;net6.0 + enable + AElf.Client.Protobuf + Protobuf using by AElf C# sdk. + AElf + true + + + + + + + + + + + + + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + + + MSBuild:Compile + + + + diff --git a/src/AElf.Client.Protobuf/Protobuf/acs0.proto b/src/AElf.Client.Protobuf/Protobuf/acs0.proto new file mode 100644 index 0000000..84606e7 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs0.proto @@ -0,0 +1,234 @@ +/** + * AElf Standards ACS0(Contract Deployment Standard) + * + * Used to manage the deployment and update of contracts. + */ +syntax = "proto3"; + +package acs0; +option csharp_namespace = "AElf.Standards.ACS0"; + +import public "aelf/core.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; + +service ACS0 { + // Deploy a system smart contract on chain and return the address of the system contract deployed. + rpc DeploySystemSmartContract (SystemContractDeploymentInput) returns (aelf.Address) { + } + + // Deploy a smart contract on chain and return the address of the contract deployed. + rpc DeploySmartContract (ContractDeploymentInput) returns (aelf.Address) { + } + + // Update a smart contract on chain. + rpc UpdateSmartContract (ContractUpdateInput) returns (aelf.Address) { + } + + // Create a proposal to deploy a new contract and returns the id of the proposed contract. + rpc ProposeNewContract (ContractDeploymentInput) returns (aelf.Hash) { + } + + // Create a proposal to check the code of a contract and return the id of the proposed contract. + rpc ProposeContractCodeCheck (ContractCodeCheckInput) returns (aelf.Hash) { + } + + // Create a proposal to update the specified contract + // and return the id of the proposed contract. + rpc ProposeUpdateContract (ContractUpdateInput) returns (aelf.Hash) { + } + + // Release the contract proposal which has been approved. + rpc ReleaseApprovedContract (ReleaseContractInput) returns (google.protobuf.Empty) { + } + + // Release the proposal which has passed the code check. + rpc ReleaseCodeCheckedContract (ReleaseContractInput) returns (google.protobuf.Empty) { + } + + // Validate whether the input system contract exists. + rpc ValidateSystemContractAddress(ValidateSystemContractAddressInput) returns (google.protobuf.Empty){ + } + + // Set authority of contract deployment. + rpc SetContractProposerRequiredState (google.protobuf.BoolValue) returns (google.protobuf.Empty) { + } + + // Get the current serial number of genesis contract + // (corresponds to the serial number that will be given to the next deployed contract). + rpc CurrentContractSerialNumber (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get detailed information about the specified contract. + rpc GetContractInfo (aelf.Address) returns (ContractInfo) { + option (aelf.is_view) = true; + } + + // Get author of the specified contract. + rpc GetContractAuthor (aelf.Address) returns (aelf.Address) { + option (aelf.is_view) = true; + } + + // Get the code hash of the contract about the specified address. + rpc GetContractHash (aelf.Address) returns (aelf.Hash) { + option (aelf.is_view) = true; + } + + // Get the address of a system contract by its name. + rpc GetContractAddressByName (aelf.Hash) returns (aelf.Address) { + option (aelf.is_view) = true; + } + + // Get the registration of a smart contract by its address. + rpc GetSmartContractRegistrationByAddress (aelf.Address) returns (aelf.SmartContractRegistration) { + option (aelf.is_view) = true; + } + + // Get the registration of a smart contract by code hash. + rpc GetSmartContractRegistrationByCodeHash (aelf.Hash) returns (aelf.SmartContractRegistration) { + option (aelf.is_view) = true; + } + + rpc GetContractCodeHashListByDeployingBlockHeight (google.protobuf.Int64Value) returns (ContractCodeHashList) { + option (aelf.is_view) = true; + } +} + +message ContractInfo +{ + // The serial number of the contract. + int64 serial_number = 1; + // The author of the contract, this is the person who deployed the contract. + aelf.Address author = 2; + // The category of contract code(0: C#). + sint32 category = 3; + // The hash of the contract code. + aelf.Hash code_hash = 4; + // Whether it is a system contract. + bool is_system_contract = 5; + // The version of the current contract. + int32 version = 6; +} + +message ContractDeploymentInput { + // The category of contract code(0: C#). + sint32 category = 1; + // The byte array of the contract code. + bytes code = 2; +} + +message SystemContractDeploymentInput { + message SystemTransactionMethodCall { + // The method name of system transaction. + string method_name = 1; + // The params of system transaction method. + bytes params = 2; + } + message SystemTransactionMethodCallList { + // The list of system transactions. + repeated SystemTransactionMethodCall value = 1; + } + // The category of contract code(0: C#). + sint32 category = 1; + // The byte array of the contract code. + bytes code = 2; + // The name of the contract. It has to be unique. + aelf.Hash name = 3; + // An initial list of transactions for the system contract, + // which is executed in sequence when the contract is deployed. + SystemTransactionMethodCallList transaction_method_call_list = 4; +} + +message ContractUpdateInput { + // The contract address that needs to be updated. + aelf.Address address = 1; + // The byte array of the new contract code. + bytes code = 2; +} + +message ContractCodeCheckInput{ + // The byte array of the contract code to be checked. + bytes contract_input = 1; + // Whether the input contract is to be deployed or updated. + bool is_contract_deployment = 2; + // Method to call after code check complete(DeploySmartContract or UpdateSmartContract). + string code_check_release_method = 3; + // The id of the proposed contract. + aelf.Hash proposed_contract_input_hash = 4; + // The category of contract code(0: C#). + sint32 category = 5; + // Indicates if the contract is the system contract. + bool is_system_contract = 6; +} + +message ContractProposed +{ + option (aelf.is_event) = true; + // The id of the proposed contract. + aelf.Hash proposed_contract_input_hash = 1; +} + +message ContractDeployed +{ + option (aelf.is_event) = true; + // The author of the contract, this is the person who deployed the contract. + aelf.Address author = 1 [(aelf.is_indexed) = true]; + // The hash of the contract code. + aelf.Hash code_hash = 2 [(aelf.is_indexed) = true]; + // The address of the contract. + aelf.Address address = 3; + // The version of the current contract. + int32 version = 4; + // The name of the contract. It has to be unique. + aelf.Hash Name = 5; +} + +message CodeCheckRequired +{ + option (aelf.is_event) = true; + // The byte array of the contract code. + bytes code = 1; + // The id of the proposed contract. + aelf.Hash proposed_contract_input_hash = 2; + // The category of contract code(0: C#). + sint32 category = 3; + // Indicates if the contract is the system contract. + bool is_system_contract = 4; +} + +message CodeUpdated +{ + option (aelf.is_event) = true; + // The address of the updated contract. + aelf.Address address = 1 [(aelf.is_indexed) = true]; + // The byte array of the old contract code. + aelf.Hash old_code_hash = 2; + // The byte array of the new contract code. + aelf.Hash new_code_hash = 3; + // The version of the current contract. + int32 version = 4; +} + +message ValidateSystemContractAddressInput { + // The name hash of the contract. + aelf.Hash system_contract_hash_name = 1; + // The address of the contract. + aelf.Address address = 2; +} + +message ReleaseContractInput { + // The hash of the proposal. + aelf.Hash proposal_id = 1; + // The id of the proposed contract. + aelf.Hash proposed_contract_input_hash = 2; +} + +message ContractCodeHashList { + repeated aelf.Hash value = 1; +} + +message ContractCodeHashMap { + map value = 1; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs1.proto b/src/AElf.Client.Protobuf/Protobuf/acs1.proto new file mode 100644 index 0000000..4894a1b --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs1.proto @@ -0,0 +1,53 @@ +/** + * AElf Standards ACS1(Transaction Fee Standard) + * + * Used to manage the transaction fee. + */ +syntax = "proto3"; + +package acs1; + +import public "aelf/options.proto"; +import public "google/protobuf/empty.proto"; +import public "google/protobuf/wrappers.proto"; +import "aelf/core.proto"; +import "authority_info.proto"; + +option (aelf.identity) = "acs1"; +option csharp_namespace = "AElf.Standards.ACS1"; + +service MethodFeeProviderContract { + + // Set the method fees for the specified method. Note that this will override all fees of the method. + rpc SetMethodFee (MethodFees) returns (google.protobuf.Empty) { + } + + // Change the method fee controller, the default is parliament and default organization. + rpc ChangeMethodFeeController (AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Query method fee information by method name. + rpc GetMethodFee (google.protobuf.StringValue) returns (MethodFees) { + option (aelf.is_view) = true; + } + + // Query the method fee controller. + rpc GetMethodFeeController (google.protobuf.Empty) returns (AuthorityInfo) { + option (aelf.is_view) = true; + } +} + +message MethodFees { + // The name of the method to be charged. + string method_name = 1; + // List of fees to be charged. + repeated MethodFee fees = 2; + bool is_size_fee_free = 3;// Optional based on the implementation of SetMethodFee method. +} + +message MethodFee { + // The token symbol of the method fee. + string symbol = 1; + // The amount of fees to be charged. + int64 basic_fee = 2; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs10.proto b/src/AElf.Client.Protobuf/Protobuf/acs10.proto new file mode 100644 index 0000000..0b6f324 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs10.proto @@ -0,0 +1,80 @@ +/** + * AElf Standards ACS10(Dividend Pool Standard) + * + * Used to construct a dividend pool in the contract. + */ +syntax = "proto3"; + +package acs10; + +import public "aelf/options.proto"; +import public "google/protobuf/empty.proto"; +import public "google/protobuf/wrappers.proto"; +import "aelf/core.proto"; + +option (aelf.identity) = "acs10"; +option csharp_namespace = "AElf.Standards.ACS10"; + +service DividendPoolContract { + // Donates tokens from the caller to the treasury. If the tokens are not native tokens in the current chain, + // they will be first converted to the native token. + rpc Donate (DonateInput) returns (google.protobuf.Empty) { + } + + // Release dividend pool according the period number. + rpc Release (ReleaseInput) returns (google.protobuf.Empty) { + } + + // Set the token symbols dividend pool supports. + rpc SetSymbolList (SymbolList) returns (google.protobuf.Empty) { + } + + // Query the token symbols dividend pool supports. + rpc GetSymbolList (google.protobuf.Empty) returns (SymbolList) { + option (aelf.is_view) = true; + } + + // Query the balance of undistributed tokens whose symbols are included in the symbol list. + rpc GetUndistributedDividends (google.protobuf.Empty) returns (Dividends) { + option (aelf.is_view) = true; + } + + // Query the dividend information according to the height. + rpc GetDividends (google.protobuf.Int64Value) returns (Dividends) { + option (aelf.is_view) = true; + } +} + +message DonateInput { + // The token symbol to donate. + string symbol = 1; + // The amount to donate. + int64 amount = 2; +} + +message ReleaseInput { + // The period number to release. + int64 period_number = 1; +} + +message SymbolList { + // The token symbol list. + repeated string value = 1; +} + +message Dividends { + // The dividends, symbol -> amount. + map value = 1; +} + +message DonationReceived { + option (aelf.is_event) = true; + // The address of donors. + aelf.Address from = 1; + // The address of dividend pool. + aelf.Address pool_contract = 2; + // The token symbol Donated. + string symbol = 3; + // The amount Donated. + int64 amount = 4; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs11.proto b/src/AElf.Client.Protobuf/Protobuf/acs11.proto new file mode 100644 index 0000000..d7708a7 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs11.proto @@ -0,0 +1,31 @@ +/** + * AElf Standards ACS11(Consensus Standard) + * + * Used to customize consensus mechanisms for cross chain. + */ +syntax = "proto3"; + +package acs11; +import "aelf/options.proto"; +import "aelf/core.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/empty.proto"; + +option (aelf.identity) = "acs11"; +option csharp_namespace = "AElf.Standards.ACS11"; + +service CrossChainInteractionContract { + // Update the consensus information of the side chain. + rpc UpdateInformationFromCrossChain (google.protobuf.BytesValue) returns (google.protobuf.Empty) { + } + + // Get the current miner list and consensus round information. + rpc GetChainInitializationInformation (google.protobuf.BytesValue) returns (google.protobuf.BytesValue) { + option (aelf.is_view) = true; + } + + // Verify that the input address is the current miner. + rpc CheckCrossChainIndexingPermission (aelf.Address) returns (google.protobuf.BoolValue) { + option (aelf.is_view) = true; + } +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs2.proto b/src/AElf.Client.Protobuf/Protobuf/acs2.proto new file mode 100644 index 0000000..637e66e --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs2.proto @@ -0,0 +1,30 @@ +/** + * AElf Standards ACS2(Parallel Execution Standard) + * + * Used to provide information for parallel execution of transactions. + */ +syntax = "proto3"; + +package acs2; + +import "aelf/core.proto"; +import "aelf/options.proto"; + +option (aelf.identity) = "acs2"; +option csharp_namespace = "AElf.Standards.ACS2"; + +service ACS2Base { + // Gets the resource information that the transaction execution depends on. + rpc GetResourceInfo (aelf.Transaction) returns (ResourceInfo) { + option (aelf.is_view) = true; + } +} + +message ResourceInfo { + // The state path that depends on when writing. + repeated aelf.ScopedStatePath write_paths = 1; + // The state path that depends on when reading. + repeated aelf.ScopedStatePath read_paths = 2; + // Whether the transaction is not executed in parallel. + bool non_parallelizable = 3; +} diff --git a/src/AElf.Client.Protobuf/Protobuf/acs3.proto b/src/AElf.Client.Protobuf/Protobuf/acs3.proto new file mode 100644 index 0000000..65ee66e --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs3.proto @@ -0,0 +1,207 @@ +/** + * AElf Standards ACS3(Contract Proposal Standard) + * + * Used for governance through proposals. + */ +syntax = "proto3"; + +package acs3; + +import public "aelf/core.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import public "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; + +option (aelf.identity) = "acs3"; +option csharp_namespace = "AElf.Standards.ACS3"; + +service AuthorizationContract { + // Create a proposal for which organization members can vote. + // When the proposal is released, a transaction will be sent to the specified contract. + // Return id of the newly created proposal. + rpc CreateProposal (CreateProposalInput) returns (aelf.Hash) { + } + + // Approve a proposal according to the proposal ID. + rpc Approve (aelf.Hash) returns (google.protobuf.Empty) { + } + + // Reject a proposal according to the proposal ID. + rpc Reject(aelf.Hash) returns (google.protobuf.Empty) { + } + + // Abstain a proposal according to the proposal ID. + rpc Abstain(aelf.Hash) returns (google.protobuf.Empty){ + } + + // Release a proposal according to the proposal ID and send a transaction to the specified contract. + rpc Release(aelf.Hash) returns (google.protobuf.Empty){ + } + + // Change the thresholds associated with proposals. + // All fields will be overwritten by the input value and this will affect all current proposals of the organization. + // Note: only the organization can execute this through a proposal. + rpc ChangeOrganizationThreshold(ProposalReleaseThreshold)returns(google.protobuf.Empty) { + } + + // Change the white list of organization proposer. + // This method overrides the list of whitelisted proposers. + rpc ChangeOrganizationProposerWhiteList(ProposerWhiteList) returns (google.protobuf.Empty){ + } + + // Create a proposal by system contracts, + // and return id of the newly created proposal. + rpc CreateProposalBySystemContract(CreateProposalBySystemContractInput) returns (aelf.Hash){ + } + + // Remove the specified proposal. If the proposal is in effect, the cleanup fails. + rpc ClearProposal(aelf.Hash) returns (google.protobuf.Empty){ + } + + // Get the proposal according to the proposal ID. + rpc GetProposal(aelf.Hash) returns (ProposalOutput) { + option (aelf.is_view) = true; + } + + // Check the existence of an organization. + rpc ValidateOrganizationExist(aelf.Address) returns (google.protobuf.BoolValue){ + option (aelf.is_view) = true; + } + + // Check if the proposer is whitelisted. + rpc ValidateProposerInWhiteList(ValidateProposerInWhiteListInput) returns (google.protobuf.BoolValue){ + option (aelf.is_view) = true; + } +} + +message CreateProposalInput { + // The name of the method to call after release. + string contract_method_name = 1; + // The address of the contract to call after release. + aelf.Address to_address = 2; + // The parameter of the method to be called after the release. + bytes params = 3; + // The timestamp at which this proposal will expire. + google.protobuf.Timestamp expired_time = 4; + // The address of the organization. + aelf.Address organization_address = 5; + // Url is used for proposal describing. + string proposal_description_url = 6; + // The token is for proposal id generation and with this token, proposal id can be calculated before proposing. + aelf.Hash token = 7; +} + +message ProposalOutput { + // The id of the proposal. + aelf.Hash proposal_id = 1; + // The method that this proposal will call when being released. + string contract_method_name = 2; + // The address of the target contract. + aelf.Address to_address = 3; + // The parameters of the release transaction. + bytes params = 4; + // The date at which this proposal will expire. + google.protobuf.Timestamp expired_time = 5; + // The address of this proposals organization. + aelf.Address organization_address = 6; + // The address of the proposer of this proposal. + aelf.Address proposer = 7; + // Indicates if this proposal is releasable. + bool to_be_released = 8; + // Approval count for this proposal. + int64 approval_count = 9; + // Rejection count for this proposal. + int64 rejection_count = 10; + // Abstention count for this proposal. + int64 abstention_count = 11; +} + +message ProposalReleaseThreshold { + // The value for the minimum approval threshold. + int64 minimal_approval_threshold = 1; + // The value for the maximal rejection threshold. + int64 maximal_rejection_threshold = 2; + // The value for the maximal abstention threshold. + int64 maximal_abstention_threshold = 3; + // The value for the minimal vote threshold. + int64 minimal_vote_threshold = 4; +} + +message ProposerWhiteList{ + // The address of the proposers + repeated aelf.Address proposers = 1; +} + +message OrganizationHashAddressPair{ + // The id of organization. + aelf.Hash organization_hash = 1; + // The address of organization. + aelf.Address organization_address = 2; +} + +message CreateProposalBySystemContractInput { + // The parameters of creating proposal. + acs3.CreateProposalInput proposal_input =1; + // The actor that trigger the call. + aelf.Address origin_proposer = 2; +} + +message ValidateProposerInWhiteListInput{ + // The address to search/check. + aelf.Address proposer = 1; + // The address of the organization. + aelf.Address organization_address = 2; +} + +message ProposalCreated{ + option (aelf.is_event) = true; + // The id of the created proposal. + aelf.Hash proposal_id = 1; + // The organization address of the created proposal. + aelf.Address organization_address=2 [(aelf.is_indexed) = true]; +} + +message ProposalReleased{ + option (aelf.is_event) = true; + // The id of the released proposal. + aelf.Hash proposal_id = 1; + // The organization address of the released proposal. + aelf.Address organization_address=2 [(aelf.is_indexed) = true]; +} + +message OrganizationCreated{ + option (aelf.is_event) = true; + // The address of the created organization. + aelf.Address organization_address = 1; +} + +message ReceiptCreated { + option (aelf.is_event) = true; + // The id of the proposal. + aelf.Hash proposal_id = 1; + // The sender address. + aelf.Address address = 2; + // The type of receipt(Approve, Reject or Abstain). + string receipt_type = 3; + // The timestamp of this method call. + google.protobuf.Timestamp time = 4; + // The address of the organization. + aelf.Address organization_address = 5 [(aelf.is_indexed) = true]; +} + +message OrganizationWhiteListChanged{ + option (aelf.is_event) = true; + // The organization address. + aelf.Address organization_address = 1; + // The new proposer whitelist. + ProposerWhiteList proposer_white_list = 2; +} + +message OrganizationThresholdChanged{ + option (aelf.is_event) = true; + // The organization address + aelf.Address organization_address = 1; + // The new release threshold. + ProposalReleaseThreshold proposer_release_threshold = 2; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs4.proto b/src/AElf.Client.Protobuf/Protobuf/acs4.proto new file mode 100644 index 0000000..0328f53 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs4.proto @@ -0,0 +1,70 @@ +/** + * AElf Standards ACS4(Consensus Standard) + * + * Used to customize consensus mechanisms. + */ +syntax = "proto3"; + +package acs4; + +import "aelf/options.proto"; +import "aelf/core.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; + +option (aelf.identity) = "acs4"; +option csharp_namespace = "AElf.Standards.ACS4"; + +service ConsensusContract { + // Generate a consensus command based on the consensus contract state and the input public key. + rpc GetConsensusCommand (google.protobuf.BytesValue) returns (ConsensusCommand) { + option (aelf.is_view) = true; + } + + // Generate consensus extra data when a block is generated. + rpc GetConsensusExtraData (google.protobuf.BytesValue) returns (google.protobuf.BytesValue) { + option (aelf.is_view) = true; + } + + // Generate consensus system transactions when a block is generated. + // Each block will contain only one consensus transaction, which is used to write the latest consensus information + // to the State database. + rpc GenerateConsensusTransactions (google.protobuf.BytesValue) returns (TransactionList) { + option (aelf.is_view) = true; + } + + // Before executing the block, verify that the consensus information in the block header is correct. + rpc ValidateConsensusBeforeExecution (google.protobuf.BytesValue) returns (ValidationResult) { + option (aelf.is_view) = true; + } + + // After executing the block, verify that the state information written to the consensus is correct. + rpc ValidateConsensusAfterExecution (google.protobuf.BytesValue) returns (ValidationResult) { + option (aelf.is_view) = true; + } +} + +message ConsensusCommand { + // Time limit of mining next block. + int32 limit_milliseconds_of_mining_block = 1; + // Context of Hint is diverse according to the consensus protocol we choose, so we use bytes. + bytes hint = 2; + // The time of arrange mining. + google.protobuf.Timestamp arranged_mining_time = 3; + // The expiration time of mining. + google.protobuf.Timestamp mining_due_time = 4; +} + +message ValidationResult { + // Is successful. + bool success = 1; + // The error message. + string message = 2; + // Whether to trigger mining again. + bool is_re_trigger = 3; +} + +message TransactionList { + // Consensus system transactions. + repeated aelf.Transaction transactions = 1; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs5.proto b/src/AElf.Client.Protobuf/Protobuf/acs5.proto new file mode 100644 index 0000000..f6de21e --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs5.proto @@ -0,0 +1,51 @@ +/** + * AElf Standards ACS5(Method Calling Threshold Contract Standard) + * + * To avoid DDOS attacks, all contracts should theoretically implement AElf Standards ACS5, + * setting a threshold for expensive methods. There are two types of call thresholds: check balance only, + * and check balance and allowance at the same time. + */ +syntax = "proto3"; + +package acs5; + +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; + +option (aelf.identity) = "acs5"; +option csharp_namespace = "AElf.Standards.ACS5"; + +service ThresholdSettingContract { + // Set the threshold for method calling. + rpc SetMethodCallingThreshold (SetMethodCallingThresholdInput) returns (google.protobuf.Empty) { + } + + // Get the threshold for method calling. + rpc GetMethodCallingThreshold (google.protobuf.StringValue) returns (MethodCallingThreshold) { + option (aelf.is_view) = true; + } +} + +message MethodCallingThreshold { + // The threshold for method calling, token symbol -> amount. + map symbol_to_amount = 1; + // The type of threshold check. + ThresholdCheckType threshold_check_type = 2; +} + +message SetMethodCallingThresholdInput { + // The method name to check. + string method = 1; + // The threshold for method calling, token symbol -> amount. + map symbol_to_amount = 2; + // The type of threshold check. + ThresholdCheckType threshold_check_type = 3; +} + +enum ThresholdCheckType { + // Check balance only. + BALANCE = 0; + // Check balance and allowance at the same time. + ALLOWANCE = 1; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs6.proto b/src/AElf.Client.Protobuf/Protobuf/acs6.proto new file mode 100644 index 0000000..f95ba5e --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs6.proto @@ -0,0 +1,22 @@ +/** + * AElf Standards ACS6(Random Number Standard) + * + * Used to generate random number. + */ +syntax = "proto3"; + +package acs6; + +import "aelf/options.proto"; +import "aelf/core.proto"; +import "google/protobuf/wrappers.proto"; + +option (aelf.identity) = "acs6"; +option csharp_namespace = "AElf.Standards.ACS6"; + +service RandomNumberProviderContract { + // Get random number according to block height. + rpc GetRandomBytes (google.protobuf.BytesValue) returns (google.protobuf.BytesValue) { + option (aelf.is_view) = true; + } +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs7.proto b/src/AElf.Client.Protobuf/Protobuf/acs7.proto new file mode 100644 index 0000000..2e9619d --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs7.proto @@ -0,0 +1,292 @@ +/** + * AElf Standards ACS7(Contract CrossChain Standard) + * + * ACS7 is for cross chain related contract implementation. + */ +syntax = "proto3"; + +package acs7; + +import public "aelf/core.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import public "google/protobuf/timestamp.proto"; + +option (aelf.identity) = "acs7"; +option csharp_namespace = "AElf.Standards.ACS7"; + +service ACS7 { + + // Propose once cross chain indexing. + rpc ProposeCrossChainIndexing(CrossChainBlockData) returns (google.protobuf.Empty) { + } + + // Release the proposed indexing if already approved. + rpc ReleaseCrossChainIndexingProposal(ReleaseCrossChainIndexingProposalInput) returns (google.protobuf.Empty) { + } + + // Request side chain creation. + rpc RequestSideChainCreation(SideChainCreationRequest) returns (google.protobuf.Empty){ + } + + // Release the side chain creation request if already approved and it will call the method CreateSideChain. + rpc ReleaseSideChainCreation(ReleaseSideChainCreationInput) returns (google.protobuf.Empty){ + } + + // Create the side chain and returns the newly created side chain ID. + // Only SideChainLifetimeController is permitted to invoke this method. + rpc CreateSideChain (CreateSideChainInput) returns (google.protobuf.Int32Value) { + } + + // Recharge for the specified side chain. + rpc Recharge (RechargeInput) returns (google.protobuf.Empty) { + } + + // Dispose a side chain according to side chain id. + // Only SideChainLifetimeController is permitted to invoke this method. + rpc DisposeSideChain (google.protobuf.Int32Value) returns (google.protobuf.Int32Value) { + } + + // Adjust side chain indexing fee. Only IndexingFeeController is permitted to invoke this method. + rpc AdjustIndexingFeePrice(AdjustIndexingFeeInput)returns(google.protobuf.Empty){ + } + + // Verify cross chain transaction. + rpc VerifyTransaction (VerifyTransactionInput) returns (google.protobuf.BoolValue) { + option (aelf.is_view) = true; + } + + // Gets all the side chain id and height of the current chain. + rpc GetSideChainIdAndHeight (google.protobuf.Empty) returns (ChainIdAndHeightDict) { + option (aelf.is_view) = true; + } + + // Get indexing information of side chains. + rpc GetSideChainIndexingInformationList (google.protobuf.Empty) returns (SideChainIndexingInformationList) { + option (aelf.is_view) = true; + } + + // Get id and recorded height of all chains. + rpc GetAllChainsIdAndHeight (google.protobuf.Empty) returns (ChainIdAndHeightDict) { + option (aelf.is_view) = true; + } + + // Get block data of indexed side chain according to height. + rpc GetIndexedSideChainBlockDataByHeight (google.protobuf.Int64Value) returns (IndexedSideChainBlockData) { + option (aelf.is_view) = true; + } + + // Get merkle path bound up with side chain according to height. + rpc GetBoundParentChainHeightAndMerklePathByHeight (google.protobuf.Int64Value) returns (CrossChainMerkleProofContext) { + option (aelf.is_view) = true; + } + + // Get initialization data for specified side chain. + rpc GetChainInitializationData (google.protobuf.Int32Value) returns (ChainInitializationData) { + option (aelf.is_view) = true; + } +} + +message SideChainBlockData { + // The height of side chain block. + int64 height = 1; + // The hash of side chain block. + aelf.Hash block_header_hash = 2; + // The merkle tree root computing from transactions status in side chain block. + aelf.Hash transaction_status_merkle_tree_root = 3; + // The id of side chain. + int32 chain_id = 4; +} + +message RechargeInput { + // The chain id to recharge. + int32 chain_id = 1; + // The amount to recharge. + int64 amount = 2; +} + +message ParentChainBlockData { + // The height of parent chain. + int64 height = 1; + // The merkle tree root computing from side chain roots. + CrossChainExtraData cross_chain_extra_data = 2; + // The parent chain id. + int32 chain_id = 3; + // The merkle tree root computing from transactions status in parent chain block. + aelf.Hash transaction_status_merkle_tree_root = 4; + // Indexed block height from side chain and merkle path for this side chain block + map indexed_merkle_path = 5; + // Extra data map. + map extra_data = 6; +} + +message CrossChainExtraData { + // Merkle tree root of side chain block transaction status root. + aelf.Hash transaction_status_merkle_tree_root = 1; +} + +message ChainIdAndHeightDict { + // A collection of chain ids and heights, where the key is the chain id and the value is the height. + map id_height_dict = 1; +} + +message SideChainIndexingInformationList { + // A list contains indexing information of side chains. + repeated SideChainIndexingInformation indexing_information_list = 1; +} + +message SideChainIndexingInformation { + // The side chain id. + int32 chain_id = 1; + // The indexed height. + int64 indexed_height = 2; +} + +message CrossChainBlockData { + // The side chain block data list to index. + repeated SideChainBlockData side_chain_block_data_list = 1; + // The parent chain block data list to index. + repeated ParentChainBlockData parent_chain_block_data_list = 2; +} + +message CrossChainMerkleProofContext { + // The height of parent chain bound up with side chain. + int64 bound_parent_chain_height = 1; + // The merkle path generated from parent chain. + aelf.MerklePath merkle_path_from_parent_chain = 2; +} + +message ChainInitializationData { + // The id of side chain. + int32 chain_id = 1; + // The side chain creator. + aelf.Address creator = 2; + // The timestamp for side chain creation. + google.protobuf.Timestamp creation_timestamp = 3; + // The height of side chain creation on parent chain. + int64 creation_height_on_parent_chain = 4; + // Creator privilege boolean flag: True if chain creator privilege preserved, otherwise false. + bool chain_creator_privilege_preserved = 5; + // Parent chain token contract address. + aelf.Address parent_chain_token_contract_address = 6; + // Initial consensus information. + ChainInitializationConsensusInfo chain_initialization_consensus_info = 7; + // The native token info. + bytes native_token_info_data = 8; + // The resource token information. + ResourceTokenInfo resource_token_info = 9; + // The chain primary token information. + ChainPrimaryTokenInfo chain_primary_token_info = 10; +} + +message ResourceTokenInfo{ + // The resource token information. + bytes resource_token_list_data = 1; + // The initial resource token amount. + map initial_resource_amount = 2; +} + +message ChainPrimaryTokenInfo{ + // The side chain primary token data. + bytes chain_primary_token_data = 1; + // The side chain primary token initial issue list. + repeated SideChainTokenInitialIssue side_chain_token_initial_issue_list = 2; +} + +message ChainInitializationConsensusInfo{ + // Initial consensus data. + bytes initial_consensus_data = 1; +} + +message SideChainCreationRequest { + // The cross chain indexing price. + int64 indexing_price = 1; + // Initial locked balance for a new side chain. + int64 locked_token_amount = 2; + // Creator privilege boolean flag: True if chain creator privilege preserved, otherwise false. + bool is_privilege_preserved = 3; + // Side chain token information. + SideChainTokenCreationRequest side_chain_token_creation_request = 4; + // A list of accounts and amounts that will be issued when the chain starts. + repeated SideChainTokenInitialIssue side_chain_token_initial_issue_list = 5; + // The initial rent resources. + map initial_resource_amount = 6; +} + +message SideChainTokenCreationRequest{ + // Token symbol of the side chain to be created + string side_chain_token_symbol = 1; + // Token name of the side chain to be created + string side_chain_token_name = 2; + // Token total supply of the side chain to be created + int64 side_chain_token_total_supply = 3; + // Token decimals of the side chain to be created + int32 side_chain_token_decimals = 4; +} + +message SideChainTokenInitialIssue{ + // The account that will be issued. + aelf.Address address = 1; + // The amount that will be issued. + int64 amount = 2; +} + +message IndexedParentChainBlockData { + // The height of the local chain when indexing the parent chain. + int64 local_chain_height = 1; + // Parent chain block data. + repeated acs7.ParentChainBlockData parent_chain_block_data_list = 2; +} + +message IndexedSideChainBlockData{ + // Side chain block data. + repeated acs7.SideChainBlockData side_chain_block_data_list = 1; +} + +message ReleaseCrossChainIndexingProposalInput{ + // List of chain ids to release. + repeated int32 chain_id_list = 1; +} + +message CreateSideChainInput{ + // The request information of the side chain creation. + SideChainCreationRequest side_chain_creation_request = 1; + // The proposer of the side chain creation. + aelf.Address proposer = 2; +} + +message ReleaseSideChainCreationInput { + // The proposal id of side chain creation. + aelf.Hash proposal_id = 1; +} + +message AdjustIndexingFeeInput{ + // The side chain id to adjust. + int32 side_chain_id = 1; + // The new price of indexing fee. + int64 indexing_fee = 2; +} + +message SideChainBlockDataIndexed{ + option (aelf.is_event) = true; +} + +message CrossChainIndexingDataProposedEvent{ + option (aelf.is_event) = true; + // Proposed cross chain data to be indexed. + acs7.CrossChainBlockData proposed_cross_chain_data = 1; + // The proposal id. + aelf.Hash proposal_id = 2; +} + +message VerifyTransactionInput { + // The cross chain transaction id to verify. + aelf.Hash transaction_id = 1; + // The merkle path of the transaction. + aelf.MerklePath path = 2; + // The height of parent chain that indexing this transaction. + int64 parent_chain_height = 3; + // The chain if to verify. + int32 verified_chain_id = 4; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs8.proto b/src/AElf.Client.Protobuf/Protobuf/acs8.proto new file mode 100644 index 0000000..a711fdf --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs8.proto @@ -0,0 +1,35 @@ +/** + * AElf Standards ACS8(Transaction Resource Token Fee Standard) + * + * ACS8 has some similarities to ACS1, both of them are charge transaction fee standard. + * The difference is that ACS1 charges the user a transaction fee, ACS8 charges the called contract, + * and the transaction fee charged by ACS8 is the specified four tokens: WRITE, READ, STORAGE, TRAFFIC. + * In another word, if a contract declares that it inherits from ACS8, each transaction in this contract will + * charge four kinds of resource token. + */ +syntax = "proto3"; + +package acs8; + +import public "aelf/options.proto"; +import public "google/protobuf/empty.proto"; + +option (aelf.identity) = "acs8"; +option csharp_namespace = "AElf.Standards.ACS8"; + +service ResourceConsumptionContract { + // Buy one of the four resource coins, which consumes the ELF balance in the contract account + // (you can recharge it yourself, or you can collect the user’s ELF tokens as a profit to be self-sufficient). + rpc BuyResourceToken (BuyResourceTokenInput) returns (google.protobuf.Empty) { + } +} + +message BuyResourceTokenInput { + // The symbol token you want to buy. + string symbol = 1; + // The amount you want to buy. + int64 amount = 2; + // Limit of cost. If the token required for buy exceeds this value, the buy will be abandoned. + // And 0 is no limit. + int64 pay_limit = 3; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/acs9.proto b/src/AElf.Client.Protobuf/Protobuf/acs9.proto new file mode 100644 index 0000000..dedf8e2 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/acs9.proto @@ -0,0 +1,52 @@ +/** + * AElf Standards ACS9 (Contract Profit Dividend Standard) + * + * Used for developers implement a profit divided mechanism on the AElf side chain. + */ +syntax = "proto3"; + +package acs9; + +import public "aelf/options.proto"; +import public "google/protobuf/empty.proto"; + +option (aelf.identity) = "acs9"; +option csharp_namespace = "AElf.Standards.ACS9"; + +service ContractProfitsContract { + // Used for the developer to collect the profits from the contract, + // and the profits will be distributed in this method. + rpc TakeContractProfits (TakeContractProfitsInput) returns (google.protobuf.Empty) { + } + + // Query the config of profit. + rpc GetProfitConfig (google.protobuf.Empty) returns (ProfitConfig) { + option (aelf.is_view) = true; + } + + // Query the profits of the contract so far. + rpc GetProfitsAmount (google.protobuf.Empty) returns (ProfitsMap) { + option (aelf.is_view) = true; + } +} + +message TakeContractProfitsInput { + // The token symbol to take. + string symbol = 1; + // The amount to take. + int64 amount = 2; +} + +message ProfitConfig { + // The portion of the profit that will be donated to the dividend pool each time the developer receives the profit. + int32 donation_parts_per_hundred = 1; + // The profit token symbol list. + repeated string profits_token_symbol_list = 2; + // The token symbol that the user can lock them to claim the profit. + string staking_token_symbol = 3; +} + +message ProfitsMap { + // The profits, token symbol -> amount. + map value = 1; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/aedpos_contract.proto b/src/AElf.Client.Protobuf/Protobuf/aedpos_contract.proto new file mode 100644 index 0000000..05546ab --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/aedpos_contract.proto @@ -0,0 +1,440 @@ +/** + * AEDPoS contract. + */ +syntax = "proto3"; + +package AEDPoS; + +import "aelf/options.proto"; +import "aelf/core.proto"; +import "authority_info.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; + +option csharp_namespace = "AElf.Contracts.Consensus.AEDPoS"; + +service AEDPoSContract { + + option (aelf.csharp_state) = "AElf.Contracts.Consensus.AEDPoS.AEDPoSContractState"; + + // Initialize the consensus contract. + rpc InitialAElfConsensusContract (InitialAElfConsensusContractInput) returns (google.protobuf.Empty) { + } + + // Initializes the consensus information in the first round. + rpc FirstRound (Round) returns (google.protobuf.Empty) { + } + + // Update consensus information. + rpc UpdateValue (UpdateValueInput) returns (google.protobuf.Empty) { + } + + // Update consensus information, create a new round. + rpc NextRound (Round) returns (google.protobuf.Empty) { + } + + // Update consensus information, create a new term. + rpc NextTerm (Round) returns (google.protobuf.Empty) { + } + + // Update consensus tiny block information. + rpc UpdateTinyBlockInformation (TinyBlockInput) returns (google.protobuf.Empty) { + } + + // Set the maximum count of miners, by default, is unlimited. + // If you want to control the count of miners, you need to set it through parliament. + rpc SetMaximumMinersCount (google.protobuf.Int32Value) returns (google.protobuf.Empty) { + } + + // The authority information for SetMaximumMinersCount, by default, is governed by parliament. + rpc ChangeMaximumMinersCountController (AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Election Contract can notify AEDPoS Contract to aware candidate replacement happened. + rpc RecordCandidateReplacement (RecordCandidateReplacementInput) returns (google.protobuf.Empty) { + } + + // Get the list of current miners. + rpc GetCurrentMinerList (google.protobuf.Empty) returns (MinerList) { + option (aelf.is_view) = true; + } + + // Get the list of current miners (hexadecimal format). + rpc GetCurrentMinerPubkeyList (google.protobuf.Empty) returns (PubkeyList) { + option (aelf.is_view) = true; + } + + // Get the list of current miners and current round number. + rpc GetCurrentMinerListWithRoundNumber (google.protobuf.Empty) returns (MinerListWithRoundNumber) { + option (aelf.is_view) = true; + } + + // Get information of the round according to round number. + rpc GetRoundInformation (google.protobuf.Int64Value) returns (Round) { + option (aelf.is_view) = true; + } + + // Get the current round number. + rpc GetCurrentRoundNumber (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the current round information. + rpc GetCurrentRoundInformation (google.protobuf.Empty) returns (Round) { + option (aelf.is_view) = true; + } + + // Get the previous round information. + rpc GetPreviousRoundInformation (google.protobuf.Empty) returns (Round) { + option (aelf.is_view) = true; + } + + // Get the current term number. + rpc GetCurrentTermNumber (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the welfare reward the current term. + rpc GetCurrentTermMiningReward (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the list of miners according to term number. + rpc GetMinerList (GetMinerListInput) returns (MinerList) { + option (aelf.is_view) = true; + } + + // Get the list of miner in previous term. + rpc GetPreviousMinerList (google.protobuf.Empty) returns (MinerList) { + option (aelf.is_view) = true; + } + + // Get the amount of mined blocks in previous term. + rpc GetMinedBlocksOfPreviousTerm (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the miner that produces the next block. + rpc GetNextMinerPubkey (google.protobuf.Empty) returns (google.protobuf.StringValue) { + option (aelf.is_view) = true; + } + + // Check to see if the account address is on the miner list for the current round. + rpc IsCurrentMiner (aelf.Address) returns (google.protobuf.BoolValue) { + option (aelf.is_view) = true; + } + + // Query the left time before the next election takes effects (seconds). + rpc GetNextElectCountDown (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get term information according term number. + rpc GetPreviousTermInformation (google.protobuf.Int64Value) returns (Round) { + option (aelf.is_view) = true; + } + + // Get random hash (Keep this for compatibility). + rpc GetRandomHash (google.protobuf.Int64Value) returns (aelf.Hash) { + option (aelf.is_view) = true; + } + + // Get the maximum of tiny blocks produced by a miner each round. + rpc GetMaximumBlocksCount (google.protobuf.Empty) returns (google.protobuf.Int32Value) { + option (aelf.is_view) = true; + } + + // Get the maximum count of miners. + rpc GetMaximumMinersCount (google.protobuf.Empty) returns (google.protobuf.Int32Value) { + option (aelf.is_view) = true; + } + + // Get the authority information for SetMaximumMinersCount. + rpc GetMaximumMinersCountController (google.protobuf.Empty) returns (AuthorityInfo) { + option (aelf.is_view) = true; + } + + // Gets the list of miners in the main chain. + rpc GetMainChainCurrentMinerList (google.protobuf.Empty) returns (MinerList) { + option (aelf.is_view) = true; + } + + // Get the list of miners in the previous term. + rpc GetPreviousTermMinerPubkeyList (google.protobuf.Empty) returns (PubkeyList) { + option (aelf.is_view) = true; + } + + // Query the current mining reward for each block. + rpc GetCurrentMiningRewardPerBlock (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } +} + +message InitialAElfConsensusContractInput { + // Whether not to change the term. + bool is_term_stay_one = 1; + // Is a side chain. + bool is_side_chain = 2; + // The number of seconds per term. + int64 period_seconds = 3; + // The interval second that increases the number of miners. + int64 miner_increase_interval = 4; +} + +message UpdateValueInput { + // Calculated from current in value. + aelf.Hash out_value = 1; + // Calculated from current in value and signatures of previous round. + aelf.Hash signature = 2; + // To ensure the values to update will be apply to correct round by comparing round id. + int64 round_id = 3; + // Publish previous in value for validation previous signature and previous out value. + aelf.Hash previous_in_value = 4; + // The actual mining time, miners must fill actual mining time when they do the mining. + google.protobuf.Timestamp actual_mining_time = 5; + // The supposed order of mining for the next round. + int32 supposed_order_of_next_round = 6; + // The tuning order of mining for the next round, miner public key -> order. + map tune_order_information = 7; + // The encrypted pieces of InValue. + map encrypted_pieces = 8; + // The decrypted pieces of InValue. + map decrypted_pieces = 9; + // The amount of produced blocks. + int64 produced_blocks = 10; + // The InValue in the previous round, miner public key -> InValue. + map miners_previous_in_values = 11; + // The irreversible block height that miner recorded. + int64 implied_irreversible_block_height = 12; +} + +message MinerList { + // The miners public key list. + repeated bytes pubkeys = 1; +} + +message PubkeyList { + // The miners public key list. + repeated string pubkeys = 1; +} + +message TermNumberLookUp { + // Term number -> Round number. + map map = 1; +} + +message Candidates { + // The candidate public keys. + repeated bytes pubkeys = 1; +} + +message Round { + // The round number. + int64 round_number = 1; + // Current miner information, miner public key -> miner information. + map real_time_miners_information = 2; + // The round number on the main chain + int64 main_chain_miners_round_number = 3; + // The time from chain start to current round (seconds). + int64 blockchain_age = 4; + // The miner public key that produced the extra block in the previous round. + string extra_block_producer_of_previous_round = 5; + // The current term number. + int64 term_number = 6; + // The height of the confirmed irreversible block. + int64 confirmed_irreversible_block_height = 7; + // The round number of the confirmed irreversible block. + int64 confirmed_irreversible_block_round_number = 8; + // Is miner list different from the the miner list in the previous round. + bool is_miner_list_just_changed = 9; + // The round id, calculated by summing block producers’ expecting time (second). + int64 round_id_for_validation = 10; +} + +message MinerInRound { + // The order of the miner producing block. + int32 order = 1; + // Is extra block producer in the current round. + bool is_extra_block_producer = 2; + // Generated by secret sharing and used for validation between miner. + aelf.Hash in_value = 3; + // Calculated from current in value. + aelf.Hash out_value = 4; + // Calculated from current in value and signatures of previous round. + aelf.Hash signature = 5; + // The expected mining time. + google.protobuf.Timestamp expected_mining_time = 6; + // The amount of produced blocks. + int64 produced_blocks = 7; + // The amount of missed time slots. + int64 missed_time_slots = 8; + // The public key of this miner. + string pubkey = 9; + // The InValue of the previous round. + aelf.Hash previous_in_value = 10; + // The supposed order of mining for the next round. + int32 supposed_order_of_next_round = 11; + // The final order of mining for the next round. + int32 final_order_of_next_round = 12; + // The actual mining time, miners must fill actual mining time when they do the mining. + repeated google.protobuf.Timestamp actual_mining_times = 13; + // The encrypted pieces of InValue. + map encrypted_pieces = 14; + // The decrypted pieces of InValue. + map decrypted_pieces = 15; + // The amount of produced tiny blocks. + int64 produced_tiny_blocks = 16; + // The irreversible block height that current miner recorded. + int64 implied_irreversible_block_height = 17; +} + +message AElfConsensusHeaderInformation { + // The sender public key. + bytes sender_pubkey = 1; + // The round information. + Round round = 2; + // The behaviour of consensus. + AElfConsensusBehaviour behaviour = 3; +} + +message AElfConsensusHint { + // The behaviour of consensus. + AElfConsensusBehaviour behaviour = 1; + // The round id. + int64 round_id = 2; + // The previous round id. + int64 previous_round_id = 3; +} + +enum AElfConsensusBehaviour { + UPDATE_VALUE = 0; + NEXT_ROUND = 1; + NEXT_TERM = 2; + NOTHING = 3; + TINY_BLOCK = 4; +} + +message AElfConsensusTriggerInformation { + // The miner public key. + bytes pubkey = 1; + // The InValue for current round. + aelf.Hash in_value = 2; + // The InValue for previous round. + aelf.Hash previous_in_value = 3; + // The behaviour of consensus. + AElfConsensusBehaviour behaviour = 4; + // The encrypted pieces of InValue. + map encrypted_pieces = 5; + // The decrypted pieces of InValue. + map decrypted_pieces = 6; + // The revealed InValues. + map revealed_in_values = 7; +} + +message TermInfo { + int64 term_number = 1; + int64 round_number = 2; +} + +message MinerListWithRoundNumber { + // The list of miners. + MinerList miner_list = 1; + // The round number. + int64 round_number = 2; +} + +message TinyBlockInput { + // The round id. + int64 round_id = 1; + // The actual mining time. + google.protobuf.Timestamp actual_mining_time = 2; + // Count of blocks currently produced + int64 produced_blocks = 3; +} + +message VoteMinersCountInput { + int32 miners_count = 1; + int64 amount = 2; +} + +message ConsensusInformation { + bytes value = 1; +} + +message GetMinerListInput { + // The term number. + int64 term_number = 1; +} + +message RandomNumberRequestInformation { + int64 target_round_number = 1;// The random hash is likely generated during this round. + int64 order = 2; + int64 expected_block_height = 3; +} + +message HashList { + repeated aelf.Hash values = 1; +} + +message LatestPubkeyToTinyBlocksCount { + // The miner public key. + string pubkey = 1; + // The count of blocks the miner produced. + int64 blocks_count = 2; +} + +message IrreversibleBlockFound { + option (aelf.is_event) = true; + // The irreversible block height found. + int64 irreversible_block_height = 1 [(aelf.is_indexed) = true]; +} + +message IrreversibleBlockHeightUnacceptable { + option (aelf.is_event) = true; + // Distance to the height of the last irreversible block. + int64 distance_to_irreversible_block_height = 1; +} + +message MiningInformationUpdated { + option (aelf.is_event) = true; + // The miner public key. + string pubkey = 1 [(aelf.is_indexed) = true]; + // The current block time. + google.protobuf.Timestamp mining_time = 2 [(aelf.is_indexed) = true]; + // The behaviour of consensus. + string behaviour = 3 [(aelf.is_indexed) = true]; + // The current block height. + int64 block_height = 4 [(aelf.is_indexed) = true]; + // The previous block hash. + aelf.Hash previous_block_hash = 5 [(aelf.is_indexed) = true]; +} + +message SecretSharingInformation { + option (aelf.is_event) = true; + // The previous round information. + Round previous_round = 1 [(aelf.is_indexed) = true]; + // The current round id. + int64 current_round_id = 2; + // The previous round id. + int64 previous_round_id = 3; +} + +message MiningRewardGenerated { + option (aelf.is_event) = true; + // The number of term the mining reward is generated. + int64 term_number = 1 [(aelf.is_indexed) = true]; + // The amount of mining reward. + int64 amount = 2; +} + +message MinerReplaced { + option (aelf.is_event) = true; + // The new miner public key. + string new_miner_pubkey = 1; +} + +message RecordCandidateReplacementInput { + string old_pubkey = 1; + string new_pubkey = 2; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/aelf/core.proto b/src/AElf.Client.Protobuf/Protobuf/aelf/core.proto new file mode 100644 index 0000000..e410996 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/aelf/core.proto @@ -0,0 +1,147 @@ +syntax = "proto3"; + +package aelf; + +option csharp_namespace = "AElf.Types"; + +message Transaction { + // The address of the sender of the transaction. + Address from = 1; + // The address of the contract when calling a contract. + Address to = 2; + // The height of the referenced block hash. + int64 ref_block_number = 3; + // The first four bytes of the referenced block hash. + bytes ref_block_prefix = 4; + // The name of a method in the smart contract at the To address. + string method_name = 5; + // The parameters to pass to the smart contract method. + bytes params = 6; + // When signing a transaction it’s actually a subset of the fields: from/to and the target method as well as + // the parameter that were given. It also contains the reference block number and prefix. + bytes signature = 10000; +} + +message StatePath { + // The partial path of the state path. + repeated string parts = 1; +} + +message ScopedStatePath { + // The scope address, which will be the contract address. + Address address = 1; + // The path of contract state. + StatePath path = 2; +} + +enum TransactionResultStatus { + // The execution result of the transaction does not exist. + NOT_EXISTED = 0; + // The transaction is in the transaction pool waiting to be packaged. + PENDING = 1; + // Transaction execution failed. + FAILED = 2; + // The transaction was successfully executed and successfully packaged into a block. + MINED = 3; + // When executed in parallel, there are conflicts with other transactions. + CONFLICT = 4; + // The transaction is waiting for validation. + PENDING_VALIDATION = 5; + // Transaction validation failed. + NODE_VALIDATION_FAILED = 6; +} + +message TransactionResult { + // The transaction id. + Hash transaction_id = 1; + // The transaction result status. + TransactionResultStatus status = 2; + // The log events. + repeated LogEvent logs = 3; + // Bloom filter for transaction logs. A transaction log event can be defined in the contract and stored + // in the bloom filter after the transaction is executed. Through this filter, we can quickly search for + // and determine whether a log exists in the transaction result. + bytes bloom = 4; + // The return value of the transaction execution. + bytes return_value = 5; + // The height of the block hat packages the transaction. + int64 block_number = 6; + // The hash of the block hat packages the transaction. + Hash block_hash = 7; + // Failed execution error message. + string error = 10; +} + +message LogEvent { + // The contract address. + Address address = 1; + // The name of the log event. + string name = 2; + // The indexed data, used to calculate bloom. + repeated bytes indexed = 3; + // The non indexed data. + bytes non_indexed = 4; +} + +message SmartContractRegistration { + // The category of contract code(0: C#). + sint32 category = 1; + // The byte array of the contract code. + bytes code = 2; + // The hash of the contract code. + Hash code_hash = 3; + // Whether it is a system contract. + bool is_system_contract = 4; + // The version of the current contract. + int32 version = 5; +} + +message TransactionExecutingStateSet { + // The changed states. + map writes = 1; + // The read states. + map reads = 2; + // The deleted states. + map deletes = 3; +} + +message Address +{ + bytes value = 1; +} + +message Hash +{ + bytes value = 1; +} + +message SInt32Value +{ + sint32 value = 1; +} + +message SInt64Value +{ + sint64 value = 1; +} + +message MerklePath { + // The merkle path nodes. + repeated MerklePathNode merkle_path_nodes = 1; +} + +message MerklePathNode{ + // The node hash. + Hash hash = 1; + // Whether it is a left child node. + bool is_left_child_node = 2; +} + +message BinaryMerkleTree { + // The leaf nodes. + repeated Hash nodes = 1; + // The root node hash. + Hash root = 2; + // The count of leaf node. + int32 leaf_count = 3; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/aelf/options.proto b/src/AElf.Client.Protobuf/Protobuf/aelf/options.proto new file mode 100644 index 0000000..34058ba --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/aelf/options.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; + +package aelf; + +import "google/protobuf/descriptor.proto"; + +option csharp_namespace = "AElf"; + +// All aelf custom options field numbers are like 50yxxx +// where y stands for the custom options type: +// 0 - FileOptions +// 1 - MessageOptions +// 2 - FieldOptions +// 3 - EnumOptions +// 4 - EnumValueOptions +// 5 - ServiceOptions +// 6 - MethodOptions + +extend google.protobuf.FileOptions { + string identity = 500001; +} + +extend google.protobuf.ServiceOptions { + repeated string base = 505001; + string csharp_state = 505030; +} + +extend google.protobuf.MethodOptions { + bool is_view = 506001; +} + +extend google.protobuf.MessageOptions { + bool is_event = 50100; +} + +extend google.protobuf.FieldOptions { + bool is_indexed = 502001; +} diff --git a/src/AElf.Client.Protobuf/Protobuf/association_contract.proto b/src/AElf.Client.Protobuf/Protobuf/association_contract.proto new file mode 100644 index 0000000..2efb821 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/association_contract.proto @@ -0,0 +1,144 @@ +/** + * Association contract. + */ +syntax = "proto3"; + +package Association; + +import "acs3.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; + +option csharp_namespace = "AElf.Contracts.Association"; + +service AssociationContract { + + option (aelf.csharp_state) = "AElf.Contracts.Association.AssociationState"; + + // Create an organization and return its address. + rpc CreateOrganization (CreateOrganizationInput) returns (aelf.Address) { + } + + // Creates an organization by system contract and return its address. + rpc CreateOrganizationBySystemContract(CreateOrganizationBySystemContractInput) returns (aelf.Address){ + } + + // Add organization members. + rpc AddMember(aelf.Address) returns (google.protobuf.Empty){ + } + + // Remove organization members. + rpc RemoveMember(aelf.Address) returns (google.protobuf.Empty){ + } + + // Replace organization member with a new member. + rpc ChangeMember(ChangeMemberInput) returns (google.protobuf.Empty){ + } + + // Get the organization according to the organization address. + rpc GetOrganization (aelf.Address) returns (Organization) { + option (aelf.is_view) = true; + } + + // Calculate the input and return the organization address. + rpc CalculateOrganizationAddress(CreateOrganizationInput) returns (aelf.Address){ + option (aelf.is_view) = true; + } +} + +message CreateOrganizationInput{ + // Initial organization members. + OrganizationMemberList organization_member_list = 1; + // The threshold for releasing the proposal. + acs3.ProposalReleaseThreshold proposal_release_threshold = 2; + // The proposer whitelist. + acs3.ProposerWhiteList proposer_white_list = 3; + // The creation token is for organization address generation. + aelf.Hash creation_token = 4; +} + +message Organization{ + // The organization members. + OrganizationMemberList organization_member_list = 1; + // The threshold for releasing the proposal. + acs3.ProposalReleaseThreshold proposal_release_threshold = 2; + // The proposer whitelist. + acs3.ProposerWhiteList proposer_white_list = 3; + // The address of organization. + aelf.Address organization_address = 4; + // The organizations id. + aelf.Hash organization_hash = 5; + // The creation token is for organization address generation. + aelf.Hash creation_token = 6; +} + +message ProposalInfo { + // The proposal ID. + aelf.Hash proposal_id = 1; + // The method that this proposal will call when being released. + string contract_method_name = 2; + // The address of the target contract. + aelf.Address to_address = 3; + // The parameters of the release transaction. + bytes params = 4; + // The date at which this proposal will expire. + google.protobuf.Timestamp expired_time = 5; + // The address of the proposer of this proposal. + aelf.Address proposer = 6; + // The address of this proposals organization. + aelf.Address organization_address = 7; + // Address list of approved. + repeated aelf.Address approvals = 8; + // Address list of rejected. + repeated aelf.Address rejections = 9; + // Address list of abstained. + repeated aelf.Address abstentions = 10; + // Url is used for proposal describing. + string proposal_description_url = 11; +} + +message OrganizationMemberList { + // The address of organization members. + repeated aelf.Address organization_members = 1; +} + +message ChangeMemberInput{ + // The old member address. + aelf.Address old_member = 1; + // The new member address. + aelf.Address new_member = 2; +} + +message CreateOrganizationBySystemContractInput { + // The parameters of creating organization. + CreateOrganizationInput organization_creation_input = 1; + // The organization address callback method which replies the organization address to caller contract. + string organization_address_feedback_method = 2; +} + +message MemberAdded{ + option (aelf.is_event) = true; + // The added member address. + aelf.Address member = 1; + // The organization address. + aelf.Address organization_address = 2 [(aelf.is_indexed) = true]; +} + +message MemberRemoved{ + option (aelf.is_event) = true; + // The removed member address. + aelf.Address member = 1; + // The organization address. + aelf.Address organization_address = 2 [(aelf.is_indexed) = true]; +} + +message MemberChanged{ + option (aelf.is_event) = true; + // The old member address. + aelf.Address old_member = 1; + // The new member address. + aelf.Address new_member = 2; + // The organization address. + aelf.Address organization_address = 3 [(aelf.is_indexed) = true]; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/authority_info.proto b/src/AElf.Client.Protobuf/Protobuf/authority_info.proto new file mode 100644 index 0000000..65302e8 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/authority_info.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +import "aelf/core.proto"; + +message AuthorityInfo { + // The contract address of the controller. + aelf.Address contract_address = 1; + // The address of the owner of the contract. + aelf.Address owner_address = 2; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/basic_contract_zero.proto b/src/AElf.Client.Protobuf/Protobuf/basic_contract_zero.proto new file mode 100644 index 0000000..5c14ec0 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/basic_contract_zero.proto @@ -0,0 +1,71 @@ +/** + * Genesis contract. + */ +syntax = "proto3"; + +package Zero; + +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "aelf/core.proto"; +import "google/protobuf/timestamp.proto"; +import "authority_info.proto"; + +option csharp_namespace = "AElf.Contracts.Genesis"; + +service BasicContractZero { + option (aelf.csharp_state) = "AElf.Contracts.Genesis.BasicContractZeroState"; + + // Initialize the genesis contract. + rpc Initialize (InitializeInput) returns (google.protobuf.Empty) { + } + + // Set initial controller address for CodeCheckController and ContractDeploymentController. + rpc SetInitialControllerAddress (aelf.Address) returns (google.protobuf.Empty) { + } + + // Modify the contract deployment controller authority. + // Note: Only old controller has permission to do this. + rpc ChangeContractDeploymentController (AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Modify the contract code check controller authority. + // Note: Only old controller has permission to do this. + rpc ChangeCodeCheckController (AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Query the ContractDeploymentController authority info. + rpc GetContractDeploymentController (google.protobuf.Empty) returns (AuthorityInfo) { + option (aelf.is_view) = true; + } + + // Query the CodeCheckController authority info. + rpc GetCodeCheckController(google.protobuf.Empty) returns (AuthorityInfo){ + option (aelf.is_view) = true; + } +} + +message InitializeInput{ + // Whether contract deployment/update requires authority. + bool contract_deployment_authority_required = 1; +} + +message ContractProposingInput{ + // The address of proposer for contract deployment/update. + aelf.Address proposer = 1; + // The status of proposal. + ContractProposingInputStatus status = 2; + // The expiration time of proposal. + google.protobuf.Timestamp expired_time = 3; +} + +enum ContractProposingInputStatus { + // Proposal is proposed. + PROPOSED = 0; + // Proposal is approved by parliament. + APPROVED = 1; + // Code check is proposed. + CODE_CHECK_PROPOSED = 2; + // Passed code checks. + CODE_CHECKED = 3; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/configuration_contract.proto b/src/AElf.Client.Protobuf/Protobuf/configuration_contract.proto new file mode 100644 index 0000000..041e726 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/configuration_contract.proto @@ -0,0 +1,52 @@ +/** + * Configuration contract. + */ +syntax = "proto3"; + +package Configuration; + +import "aelf/core.proto"; +import "google/protobuf/wrappers.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "authority_info.proto"; + +option csharp_namespace = "AElf.Contracts.Configuration"; + +service Configuration { + option (aelf.csharp_state) = "AElf.Contracts.Configuration.ConfigurationState"; + + // Add or update configuration. + rpc SetConfiguration (SetConfigurationInput) returns (google.protobuf.Empty) { + } + + // Change the method fee controller, the default is Parliament. + rpc ChangeConfigurationController (AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Query the configuration by configuration’s key. + rpc GetConfiguration (google.protobuf.StringValue) returns (google.protobuf.BytesValue) { + option (aelf.is_view) = true; + } + + // Query the controller information + rpc GetConfigurationController (google.protobuf.Empty) returns (AuthorityInfo) { + option (aelf.is_view) = true; + } + +} + +message SetConfigurationInput { + // The configuration’s key. + string key = 1; + // The configuration’s value(binary data). + bytes value = 2; +} + +message ConfigurationSet { + option (aelf.is_event) = true; + // The configuration’s key. + string key = 1; + // The configuration’s value(binary data). + bytes value = 2; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/cross_chain_contract.proto b/src/AElf.Client.Protobuf/Protobuf/cross_chain_contract.proto new file mode 100644 index 0000000..5441a66 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/cross_chain_contract.proto @@ -0,0 +1,266 @@ +/** + * Cross-Chain contract. + */ +syntax = "proto3"; + +package CrossChain; + +import "acs7.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "authority_info.proto"; + +option csharp_namespace = "AElf.Contracts.CrossChain"; + +service CrossChainContract { + + option (aelf.csharp_state) = "AElf.Contracts.CrossChain.CrossChainContractState"; + + // Propose once cross chain indexing. + rpc Initialize (InitializeInput) returns (google.protobuf.Empty) { + } + + // Set the initial SideChainLifetimeController address which should be parliament organization by default. + rpc SetInitialSideChainLifetimeControllerAddress(aelf.Address) returns (google.protobuf.Empty){ + } + + // Set the initial CrossChainIndexingController address which should be parliament organization by default. + rpc SetInitialIndexingControllerAddress(aelf.Address) returns (google.protobuf.Empty){ + } + + // Change the cross chain indexing controller. + rpc ChangeCrossChainIndexingController(AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Change the lifetime controller of the side chain. + rpc ChangeSideChainLifetimeController(AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Change indexing fee adjustment controller for specific side chain. + rpc ChangeSideChainIndexingFeeController(ChangeSideChainIndexingFeeControllerInput) returns (google.protobuf.Empty){ + } + + // When the indexing proposal is released, clean up the pending proposal. + rpc AcceptCrossChainIndexingProposal(AcceptCrossChainIndexingProposalInput) returns (google.protobuf.Empty){ + } + + // Get the side chain creator address according to side chain id. + rpc GetSideChainCreator (google.protobuf.Int32Value) returns (aelf.Address) { + option (aelf.is_view) = true; + } + + // Get the current status of side chain according to side chain id. + rpc GetChainStatus (google.protobuf.Int32Value) returns (GetChainStatusOutput) { + option (aelf.is_view) = true; + } + + // Get the side chain height according to side chain id. + rpc GetSideChainHeight (google.protobuf.Int32Value) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the height of parent chain. + rpc GetParentChainHeight (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the chain id of parent chain. + rpc GetParentChainId (google.protobuf.Empty) returns (google.protobuf.Int32Value) { + option (aelf.is_view) = true; + } + + // Get the balance of side chain indexing according to side chain id. + rpc GetSideChainBalance (google.protobuf.Int32Value) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the fee debt of side chain indexing according to side chain id. + rpc GetSideChainIndexingFeeDebt (google.protobuf.Int32Value) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the status of the current indexing proposal. + rpc GetIndexingProposalStatus (google.protobuf.Empty) returns (GetIndexingProposalStatusOutput) { + option (aelf.is_view) = true; + } + + // Get the side chain indexing fee price according to side chain id. + rpc GetSideChainIndexingFeePrice(google.protobuf.Int32Value) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the lifetime controller of the side chain. + rpc GetSideChainLifetimeController(google.protobuf.Empty) returns (AuthorityInfo){ + option (aelf.is_view) = true; + } + + // Get the cross chain indexing controller. + rpc GetCrossChainIndexingController(google.protobuf.Empty) returns (AuthorityInfo){ + option (aelf.is_view) = true; + } + + // Get the indexing fee controller of side chain according to side chain id. + rpc GetSideChainIndexingFeeController(google.protobuf.Int32Value) returns (AuthorityInfo){ + option (aelf.is_view) = true; + } +} + +message InitializeInput { + // The id of parent chain. + int32 parent_chain_id = 1; + // The height of side chain created on parent chain. + int64 creation_height_on_parent_chain = 2; + // True if chain privilege needed, otherwise false. + bool is_privilege_preserved = 3; +} + +message SideChainCreatedEvent { + option (aelf.is_event) = true; + // The proposer who propose to create the side chain. + aelf.Address creator = 1; + // The created side chain id. + int32 chainId = 2; +} + +message Disposed { + option (aelf.is_event) = true; + // The disposed side chain id. + int32 chain_id = 1; +} + +message ProposedCrossChainIndexing{ + // The collection of chain indexing proposal, the key is chain id. + map chain_indexing_proposal_collections = 1; +} + +message ChainIndexingProposal{ + // The id of cross chain indexing proposal. + aelf.Hash proposal_id = 1; + // The proposer of cross chain indexing. + aelf.Address proposer = 2; + // The cross chain data proposed. + acs7.CrossChainBlockData proposed_cross_chain_block_data = 3; + // The status of of cross chain indexing proposal. + CrossChainIndexingProposalStatus status = 4; + // The chain id of the indexing. + int32 chain_id = 5; +} + +message GetIndexingProposalStatusOutput{ + // The collection of pending indexing proposal, the key is chain id. + map chain_indexing_proposal_status = 1; +} + +message PendingChainIndexingProposalStatus{ + // The id of cross chain indexing proposal. + aelf.Hash proposal_id = 1; + // The proposer of cross chain indexing. + aelf.Address proposer = 2; + // True if the proposal can be released, otherwise false. + bool to_be_released = 3; + // The cross chain data proposed. + acs7.CrossChainBlockData proposed_cross_chain_block_data = 4; + // The proposal expiration time. + google.protobuf.Timestamp expired_time = 5; +} + +message GetPendingCrossChainIndexingProposalOutput{ + // The proposal id of cross chain indexing. + aelf.Hash proposal_id = 1; + // The proposer of cross chain indexing proposal. + aelf.Address proposer = 2; + // True if the proposal can be released, otherwise false. + bool to_be_released = 3; + // The cross chain data proposed. + acs7.CrossChainBlockData proposed_cross_chain_block_data = 4; + // The proposal expiration time. + google.protobuf.Timestamp expired_time = 5; +} + +enum CrossChainIndexingProposalStatus{ + NON_PROPOSED = 0; + // The proposal is pending. + PENDING = 1; + // The proposal has been released. + ACCEPTED = 2; +} + +enum SideChainStatus +{ + // Currently no meaning. + FATAL = 0; + // The side chain is being indexed. + ACTIVE = 1; + // The side chain is in debt for indexing fee. + INDEXING_FEE_DEBT = 2; + // The side chain is disposed. + TERMINATED = 3; +} + +message SideChainInfo { + // The proposer who propose to create the side chain. + aelf.Address proposer = 1; + // The status of side chain. + SideChainStatus side_chain_status = 2; + // The side chain id. + int32 side_chain_id = 3; + // The time of side chain created. + google.protobuf.Timestamp creation_timestamp = 4; + // The height of side chain created on parent chain. + int64 creation_height_on_parent_chain = 5; + // The price of indexing fee. + int64 indexing_price = 6; + // True if chain privilege needed, otherwise false. + bool is_privilege_preserved = 7; + // creditor and amounts for the chain indexing fee debt + map arrears_info = 8; + // The controller of indexing fee. + AuthorityInfo indexing_fee_controller = 9; +} + +message GetChainStatusOutput{ + // The status of side chain. + SideChainStatus status = 1; +} + +message SideChainCreationRequestState{ + // The parameters of creating side chain. + acs7.SideChainCreationRequest side_chain_creation_request = 1; + // The expiration date of the proposal. + google.protobuf.Timestamp expired_time = 2; + // The proposer who proposed to create the side chain. + aelf.Address proposer = 3; +} + +message ChangeSideChainIndexingFeeControllerInput{ + // The side chain id. + int32 chain_id = 1; + // The changed controller of indexing fee. + AuthorityInfo authority_info = 2; +} + +message SideChainLifetimeControllerChanged{ + option (aelf.is_event) = true; + // The changed controller of side chain lifetime. + AuthorityInfo authority_info = 1; +} + +message CrossChainIndexingControllerChanged{ + option (aelf.is_event) = true; + // The changed controller of indexing. + AuthorityInfo authority_info = 1; +} + +message SideChainIndexingFeeControllerChanged{ + option (aelf.is_event) = true; + // The side chain id. + int32 chain_id = 1 [(aelf.is_indexed) = true]; + // The changed controller of side chain indexing fee. + AuthorityInfo authority_info = 2; +} + +message AcceptCrossChainIndexingProposalInput{ + // The chain id of accepted indexing. + int32 chain_id = 1; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/economic_contract.proto b/src/AElf.Client.Protobuf/Protobuf/economic_contract.proto new file mode 100644 index 0000000..943fe74 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/economic_contract.proto @@ -0,0 +1,62 @@ +/** + * Economic contract. + */ +syntax = "proto3"; + +package Economic; + +import "aelf/core.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; + +option csharp_namespace = "AElf.Contracts.Economic"; + +service EconomicContract { + option (aelf.csharp_state) = "AElf.Contracts.Economic.EconomicContractState"; + + // Only ZeroContract is able to issue the native token. + rpc IssueNativeToken (IssueNativeTokenInput) returns (google.protobuf.Empty) { + } + + // It will initialize other contracts related to economic activities (For instance, create the native token). + // This transaction only can be send once because after the first sending, its state will be set to initialized. + rpc InitialEconomicSystem (InitialEconomicSystemInput) returns (google.protobuf.Empty) { + } +} + +message InitialEconomicSystemInput { + // The native token symbol. + string native_token_symbol = 1; + // The native token name. + string native_token_name = 2; + // The native token total supply. + int64 native_token_total_supply = 3; + // The accuracy of the native token. + int32 native_token_decimals = 4; + // It indicates if the token is burnable. + bool is_native_token_burnable = 5; + // It determines how much native token is used to reward the miners. + int64 mining_reward_total_amount = 6; + // todo : remove unused fields + int64 transaction_size_fee_unit_price = 7; +} + +message IssueNativeTokenInput { + // The amount of token. + int64 amount = 1; + // The memo. + string memo = 2; + // The recipient of the token. + aelf.Address to = 3; +} + +message IssueResourceTokenInput { + // The symbol of resource token. + string symbol = 1; + // The amount of resource token. + int64 amount = 2; + // The memo. + string memo = 3; + // The recipient of the token. + aelf.Address to = 4; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/election_contract.proto b/src/AElf.Client.Protobuf/Protobuf/election_contract.proto new file mode 100644 index 0000000..0337e7c --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/election_contract.proto @@ -0,0 +1,522 @@ +/** + * Election contract. + */ +syntax = "proto3"; + +package Election; + +import "aelf/core.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/empty.proto"; +import "aelf/options.proto"; +import "authority_info.proto"; + +option csharp_namespace = "AElf.Contracts.Election"; + +service ElectionContract { + + option (aelf.csharp_state) = "AElf.Contracts.Election.ElectionContractState"; + + // Initialize the election contract. + rpc InitialElectionContract (InitialElectionContractInput) returns (google.protobuf.Empty) { + } + + // Register a new voting item through vote contract. + rpc RegisterElectionVotingEvent (google.protobuf.Empty) returns (google.protobuf.Empty) { + } + + // Take snapshot according to term number, and distribute profits. + rpc TakeSnapshot (TakeElectionSnapshotInput) returns (google.protobuf.Empty) { + } + + // To be a block producer, a user should first register to be a candidate and lock some token as a deposit. + // If the data center is not full, the user will be added in automatically and get one weight + // for sharing bonus in the future. + rpc AnnounceElection (aelf.Address) returns (google.protobuf.Empty) { + } + + // A candidate is able to quit the election provided he is not currently elected. If you quit successfully, + // the candidate will get his locked tokens back and will not receive anymore bonus. + rpc QuitElection (google.protobuf.StringValue) returns (google.protobuf.Empty) { + } + + // Used for voting for a candidate to be elected. The tokens you vote with will be locked until the end time. + // According to the number of token you voted and its lock time, you can get corresponding weight for + // sharing the bonus in the future. And return the vote id. + rpc Vote (VoteMinerInput) returns (aelf.Hash) { + } + + // Before the end time, you are able to change your vote target to other candidates. + rpc ChangeVotingOption (ChangeVotingOptionInput) returns (google.protobuf.Empty) { + } + + rpc FixWelfareProfit (FixWelfareProfitInput) returns (google.protobuf.Empty) { + } + + rpc DisableWelfareFix (google.protobuf.Empty) returns (google.protobuf.Empty) { + } + + // After the lock time, your locked tokens will be unlocked and you can withdraw them according to the vote id. + rpc Withdraw (aelf.Hash) returns (google.protobuf.Empty) { + } + + // Update candidate information by consensus contract. + rpc UpdateCandidateInformation (UpdateCandidateInformationInput) returns (google.protobuf.Empty) { + } + + // Batch update candidate information by consensus contract. + rpc UpdateMultipleCandidateInformation (UpdateMultipleCandidateInformationInput) returns (google.protobuf.Empty) { + } + + // Update the count of miner by consensus contract. + rpc UpdateMinersCount (UpdateMinersCountInput) returns (google.protobuf.Empty) { + } + + // Set the treasury profit ids. + rpc SetTreasurySchemeIds (SetTreasurySchemeIdsInput) returns (google.protobuf.Empty) { + } + + // Set the weight of vote interest. + rpc SetVoteWeightInterest (VoteWeightInterestList) returns (google.protobuf.Empty) { + } + + // Set the weight of lock time and votes in the calculation of voting weight. + rpc SetVoteWeightProportion (VoteWeightProportion) returns (google.protobuf.Empty) { + } + + // Change the controller for the weight of vote interest. + rpc ChangeVoteWeightInterestController (AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Candidate admin can replace candidate pubkey with a new pubkey. + rpc ReplaceCandidatePubkey (ReplaceCandidatePubkeyInput) returns (google.protobuf.Empty) { + } + + // Set admin address of candidate (mostly supply) + rpc SetCandidateAdmin (SetCandidateAdminInput) returns (google.protobuf.Empty) { + } + + rpc RemoveEvilNode (google.protobuf.StringValue) returns (google.protobuf.Empty) { + } + + // Views + + // Get all candidates’ public keys. + rpc GetCandidates (google.protobuf.Empty) returns (PubkeyList) { + option (aelf.is_view) = true; + } + + // Get all candidates whose number of votes is greater than 0. + rpc GetVotedCandidates (google.protobuf.Empty) returns (PubkeyList) { + option (aelf.is_view) = true; + } + + // Get a candidate’s information. + rpc GetCandidateInformation (google.protobuf.StringValue) returns (CandidateInformation) { + option (aelf.is_view) = true; + } + + // Get the victories of the latest term. + rpc GetVictories (google.protobuf.Empty) returns (PubkeyList) { + option (aelf.is_view) = true; + } + + // Get the snapshot of term according to term number. + rpc GetTermSnapshot (GetTermSnapshotInput) returns (TermSnapshot) { + option (aelf.is_view) = true; + } + + // Get the count of miner. + rpc GetMinersCount (google.protobuf.Empty) returns (google.protobuf.Int32Value) { + option (aelf.is_view) = true; + } + + // Get the election result according to term id. + rpc GetElectionResult (GetElectionResultInput) returns (ElectionResult) { + option (aelf.is_view) = true; + } + + // Get the voter information according to voter public key. + rpc GetElectorVote (google.protobuf.StringValue) returns (ElectorVote) { + option (aelf.is_view) = true; + } + + // Gets the voter information including the active voting records (excluding withdrawn voting records.). + rpc GetElectorVoteWithRecords (google.protobuf.StringValue) returns (ElectorVote) { + option (aelf.is_view) = true; + } + + // Gets the voter information including the active and withdrawn voting records. + rpc GetElectorVoteWithAllRecords (google.protobuf.StringValue) returns (ElectorVote) { + option (aelf.is_view) = true; + } + + // Get voting information for candidate according to the public key of the candidate. + rpc GetCandidateVote (google.protobuf.StringValue) returns (CandidateVote) { + option (aelf.is_view) = true; + } + + // Get voting information for candidate according to the public key of the candidate. + rpc GetCandidateVoteWithRecords (google.protobuf.StringValue) returns (CandidateVote) { + option (aelf.is_view) = true; + } + + // Get voting information for candidate according to the public key of the candidate + // (including the active and withdrawn voting records). + rpc GetCandidateVoteWithAllRecords (google.protobuf.StringValue) returns (CandidateVote) { + option (aelf.is_view) = true; + } + + // Get the total number of voters. + rpc GetVotersCount (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get the total number of vote token. + rpc GetVotesAmount (google.protobuf.Empty) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Get candidate information according to the index and length. + rpc GetPageableCandidateInformation (PageInformation) returns (GetPageableCandidateInformationOutput) { + option (aelf.is_view) = true; + } + + // Get the voting item id of miner election. + rpc GetMinerElectionVotingItemId (google.protobuf.Empty) returns (aelf.Hash) { + option (aelf.is_view) = true; + } + + // Get the data center ranking list. + rpc GetDataCenterRankingList (google.protobuf.Empty) returns (DataCenterRankingList) { + option (aelf.is_view) = true; + } + + // Get the weight of vote interest. + rpc GetVoteWeightSetting (google.protobuf.Empty) returns (VoteWeightInterestList) { + option (aelf.is_view) = true; + } + + // Get the weight of lock time and votes in the calculation of voting weight. + rpc GetVoteWeightProportion (google.protobuf.Empty) returns (VoteWeightProportion) { + option (aelf.is_view) = true; + } + + // Used to calculate the bonus weights that users can get by voting. + rpc GetCalculateVoteWeight (VoteInformation) returns (google.protobuf.Int64Value){ + option (aelf.is_view) = true; + } + + // Query the controller for the weight of vote interest. + rpc GetVoteWeightInterestController (google.protobuf.Empty) returns (AuthorityInfo) { + option (aelf.is_view) = true; + } + + // Inspect the evil nodes included in the specified miners and return to the replacement node. + rpc GetMinerReplacementInformation (GetMinerReplacementInformationInput) returns (MinerReplacementInformation) { + option (aelf.is_view) = true; + } + + // Query candidate admin. + rpc GetCandidateAdmin (google.protobuf.StringValue) returns (aelf.Address) { + option (aelf.is_view) = true; + } + + // Query the newest pubkey of an old pubkey. + rpc GetNewestPubkey (google.protobuf.StringValue) returns (google.protobuf.StringValue) { + option (aelf.is_view) = true; + } + + // Query the old pubkey. + rpc GetReplacedPubkey (google.protobuf.StringValue) returns (google.protobuf.StringValue) { + option (aelf.is_view) = true; + } +} + +message InitialElectionContractInput { + // Minimum number of seconds for locking. + int64 minimum_lock_time = 1; + // Maximum number of seconds for locking. + int64 maximum_lock_time = 2; + // The current miner list. + repeated string miner_list = 3; + // The number of seconds per term. + int64 time_each_term = 4; + // The interval second that increases the number of miners. + int64 miner_increase_interval = 5; +} + +message GetTermSnapshotInput { + // The term number. + int64 term_number = 1; +} + +message UpdateCandidateInformationInput { + // The candidate public key. + string pubkey = 1; + // The number of blocks recently produced. + int64 recently_produced_blocks = 2; + // The number of time slots recently missed. + int64 recently_missed_time_slots = 3; + // Is it a evil node. If true will remove the candidate. + bool is_evil_node = 4; +} + +message UpdateMultipleCandidateInformationInput { + // The candidate information to update. + repeated UpdateCandidateInformationInput value = 1; +} + +message TakeElectionSnapshotInput { + // The term number to take snapshot. + int64 term_number = 1; + // The number of mined blocks of this term. + int64 mined_blocks = 2; + // The end round number of this term. + int64 round_number = 3; +} + +message VoteMinerInput { + // The candidate public key. + string candidate_pubkey = 1; + // The amount token to vote. + int64 amount = 2; + // The end timestamp of this vote. + google.protobuf.Timestamp end_timestamp = 3; + // Used to generate vote id. + aelf.Hash token = 4; +} + +message ChangeVotingOptionInput { + // The vote id to change. + aelf.Hash vote_id = 1; + // The new candidate public key. + string candidate_pubkey = 2; + // Tokens will be locked another previous locking time if this is true. + bool is_reset_voting_time = 3; +} + +message FixWelfareProfitInput { + repeated FixWelfareProfitInfo fix_info_list = 1; +} + +message FixWelfareProfitInfo { + aelf.Hash vote_id = 1; + int64 start_period = 2; + int64 end_period = 3; +} + +message UpdateTermNumberInput { + // The term number. + int64 term_number = 1; +} + +message GetElectionResultInput { + // The term number. + int64 term_number = 1; +} + +message ElectionResult { + // The term number + int64 term_number = 1; + // The election result, candidates’ public key -> number of votes. + map results = 2; + // Whether an election is currently being held. + bool is_active = 3; +} + +message ElectorVote { + // The active voting record ids. + repeated aelf.Hash active_voting_record_ids = 1; + // The voting record ids that were withdrawn. + repeated aelf.Hash withdrawn_voting_record_ids = 2; + // The total number of active votes. + int64 active_voted_votes_amount = 3; + // The total number of votes (including the number of votes withdrawn). + int64 all_voted_votes_amount = 4; + // The active voting records. + repeated ElectionVotingRecord active_voting_records = 5; + // The voting records that were withdrawn. + repeated ElectionVotingRecord withdrawn_votes_records = 6; + // Public key for voter. + bytes pubkey = 7; +} + +message CandidateVote { + // The active voting record ids obtained. + repeated aelf.Hash obtained_active_voting_record_ids = 1; + // The active voting record ids that were withdrawn. + repeated aelf.Hash obtained_withdrawn_voting_record_ids = 2; + // The total number of active votes obtained. + int64 obtained_active_voted_votes_amount = 3; + // The total number of votes obtained. + int64 all_obtained_voted_votes_amount = 4; + // The active voting records. + repeated ElectionVotingRecord obtained_active_voting_records = 5; + // The voting records that were withdrawn. + repeated ElectionVotingRecord obtained_withdrawn_votes_records = 6; + // Public key for candidate. + bytes pubkey = 7; +} + +message CandidateInformation { + // Candidate’s public key. + string pubkey = 1; + // The number of terms that the candidate is elected. + repeated int64 terms = 2; + // The number of blocks the candidate has produced. + int64 produced_blocks = 3; + // The time slot for which the candidate failed to produce blocks. + int64 missed_time_slots = 4; + // The count of continual appointment. + int64 continual_appointment_count = 5; + // The transaction id when the candidate announced. + aelf.Hash announcement_transaction_id = 6; + // Indicate whether the candidate can be elected in the current term. + bool is_current_candidate = 7; +} + +message CandidateDetail { + // The candidate information. + CandidateInformation candidate_information = 1; + // The number of votes a candidate has obtained. + int64 obtained_votes_amount = 2; +} + +message ElectionVotingRecord { + // The address of voter. + aelf.Address voter = 1; + // The public key of candidate. + string candidate = 2; + // Amount of voting. + int64 amount = 3; + // The term number of voting. + int64 term_number = 4; + // The vote id. + aelf.Hash vote_id = 5; + // Vote lock time. + int64 lock_time = 6; + // The unlock timestamp. + google.protobuf.Timestamp unlock_timestamp = 7; + // The withdraw timestamp. + google.protobuf.Timestamp withdraw_timestamp = 8; + // The vote timestamp. + google.protobuf.Timestamp vote_timestamp = 9; + // Indicates if the vote has been withdrawn. + bool is_withdrawn = 10; + // Vote weight for sharing bonus. + int64 weight = 11; + // Whether vote others. + bool is_change_target = 12; +} + +message PageInformation { + // The start index. + int32 start = 1; + // The number of records. + int32 length = 2; +} + +message PubkeyList { + // Candidates’ public keys + repeated bytes value = 1; +} + +message TermSnapshot { + // The end round number of this term. + int64 end_round_number = 1; + // The number of blocks mined in this term. + int64 mined_blocks = 2; + // The election result, candidates’ public key -> number of votes. + map election_result = 3; +} + +message UpdateMinersCountInput { + // The count of miner. + int32 miners_count = 1; +} + +message GetPageableCandidateInformationOutput { + // The details of the candidates. + repeated CandidateDetail value = 1; +} + +message SetTreasurySchemeIdsInput { + // The scheme id of treasury reward. + aelf.Hash treasury_hash = 1; + // The scheme id of welfare reward. + aelf.Hash welfare_hash = 2; + // The scheme id of subsidy reward. + aelf.Hash subsidy_hash = 3; + // The scheme id of welcome reward. + aelf.Hash welcome_hash = 4; + // The scheme id of flexible reward. + aelf.Hash flexible_hash = 5; +} + +message DataCenterRankingList { + // The top n * 5 candidates with vote amount, candidate public key -> vote amount. + map data_centers = 1; +} + +message VoteWeightInterest{ + // Number of days locked. + int32 day = 1; + // Locked interest. + int32 interest = 2; + int32 capital = 3; +} + +message VoteWeightInterestList { + // The weight of vote interest. + repeated VoteWeightInterest vote_weight_interest_infos = 1; +} + +message VoteWeightProportion { + // The weight of lock time. + int32 time_proportion = 1; + // The weight of the votes cast. + int32 amount_proportion = 2; +} + +message VoteInformation{ + // Amount of voting. + int64 amount = 1; + // Vote lock time. + int64 lock_time = 2; +} + +message GetMinerReplacementInformationInput { + // The current miner list to inspect. + repeated string current_miner_list = 1; +} + +message MinerReplacementInformation { + // The alternative candidate public keys. + repeated string alternative_candidate_pubkeys = 1; + // The evil miner public keys. + repeated string evil_miner_pubkeys = 2; +} + +message ReplaceCandidatePubkeyInput { + string old_pubkey = 1; + string new_pubkey = 2; +} + +message SetCandidateAdminInput { + string pubkey = 1; + aelf.Address admin = 2; +} + +message EvilMinerDetected { + option (aelf.is_event) = true; + // The public key of evil miner. + string pubkey = 1; +} + +message CandidatePubkeyReplaced { + option (aelf.is_event) = true; + string old_pubkey = 1; + string new_pubkey = 2; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/kernel.proto b/src/AElf.Client.Protobuf/Protobuf/kernel.proto new file mode 100644 index 0000000..4a9c404 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/kernel.proto @@ -0,0 +1,183 @@ +syntax = "proto3"; + +package aelf; + +import "google/protobuf/timestamp.proto"; +import "aelf/core.proto"; + +option csharp_namespace = "AElf.Kernel"; + +enum TransactionStatus { + UNKNOWN_TRANSACTION_STATUS = 0; + TRANSACTION_EXECUTING = 1; + TRANSACTION_EXECUTED = 2; +} + +message StateValue { + bytes current_value = 1; + bytes original_value = 2; +} + +message StateChange { + StatePath state_path = 1; + StateValue state_value = 2; +} + +// For failed transactions, its status follows the Min of +// its own status and its inline transactions' +enum ExecutionStatus { + UNDEFINED = 0; + // Successful => + EXECUTED = 1; + + // Failed => + // Infrastructure reasons + CANCELED = -1; + SYSTEM_ERROR = -2; + + // Contract reasons + CONTRACT_ERROR = -10; + EXCEEDED_MAX_CALL_DEPTH = -11; + + // Pre-failed + PREFAILED = -99; + + // Post-failed + POSTFAILED = -199; +} + +message TransactionTrace { + Hash transaction_id = 1; + bytes return_value = 2; + string error = 3; + repeated Transaction pre_transactions = 4; + repeated TransactionTrace pre_traces = 5; + repeated Transaction inline_transactions = 6; + repeated TransactionTrace inline_traces = 7; + repeated Transaction post_transactions = 8; + repeated TransactionTrace post_traces = 9; + repeated LogEvent logs = 10; + int64 elapsed = 11; + ExecutionStatus execution_status = 12; + TransactionExecutingStateSet state_set = 13; +} + +message ExecutionReturnSet { + Hash transaction_id = 1; + TransactionResultStatus status = 2; + map state_changes = 3; + map state_accesses = 4; + bytes bloom = 5; + bytes return_value = 6; + map state_deletes = 7; + TransactionResult transaction_result = 8; +} + +message BlockHeaderList { + repeated BlockHeader headers = 1; +} + +message BlockHeader { + int32 version = 1; + int32 chain_id = 2; + Hash previous_block_hash = 3; + Hash merkle_tree_root_of_transactions = 4; + Hash merkle_tree_root_of_world_state = 5; + bytes bloom = 6; + int64 height = 7; + map extra_data = 8; + google.protobuf.Timestamp time = 9; + Hash merkle_tree_root_of_transaction_status = 10; + bytes signer_pubkey = 9999; + bytes signature = 10000; +} + +message BlockBody { + repeated Hash transaction_ids = 1; +} + +message Block { + BlockHeader header = 1; + BlockBody body = 2; +} + +message VersionedState { + string key = 1; + bytes value = 2; + int64 block_height = 3; + Hash block_hash = 4; + Hash origin_block_hash = 5; +} + +message BlockStateSet { + Hash block_hash = 1; + Hash previous_hash = 2; + int64 block_height = 3; + map changes = 4; + repeated string deletes = 5; + map block_executed_data = 6; +} + +enum ChainStateMergingStatus { + COMMON = 0; + MERGING = 1; + MERGED = 2; +} + +message ChainStateInfo { + int32 chain_id = 1; + Hash block_hash = 2; + int64 block_height = 3; + Hash merging_block_hash = 4; + ChainStateMergingStatus status = 5; +} + +enum ChainBlockLinkExecutionStatus { + EXECUTION_NONE = 0; + EXECUTION_SUCCESS = 1; + EXECUTION_FAILED = 2; +} + +message ChainBlockLink { + Hash block_hash = 1; + int64 height = 2; + Hash previous_block_hash = 3; + ChainBlockLinkExecutionStatus execution_status = 4; + bool is_irreversible_block = 5; + bool is_linked = 6; + bool is_light_block = 7; //no block body +} + +message Chain { + int32 id = 1; + Hash genesis_block_hash = 2; + Hash longest_chain_hash = 3; + int64 longest_chain_height = 4; + map branches = 5; + map not_linked_blocks = 6; + Hash last_irreversible_block_hash = 7; + int64 last_irreversible_block_height = 8; + Hash best_chain_hash = 9; + int64 best_chain_height = 10; +} + +message ChainBlockIndex { + Hash block_hash = 1; +} + +message BlockIndex{ + Hash block_hash = 1; + int64 block_height = 2; +} + +message TransactionBlockIndex { + Hash block_hash = 1; + int64 block_height = 2; + repeated BlockIndex previous_execution_block_index_list = 3; +} + +message SmartContractAddress{ + Address address = 1; + Hash block_hash = 2; + int64 block_height = 3; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/parliament_contract.proto b/src/AElf.Client.Protobuf/Protobuf/parliament_contract.proto new file mode 100644 index 0000000..c7a8936 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/parliament_contract.proto @@ -0,0 +1,148 @@ +/** + * Parliament contract. + */ +syntax = "proto3"; + +package Parliament; + +import "acs3.proto"; +import public "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; + +option csharp_namespace = "AElf.Contracts.Parliament"; + +service ParliamentContract { + + option (aelf.csharp_state) = "AElf.Contracts.Parliament.ParliamentState"; + + // Initialize parliament proposer whitelist and create the first parliament organization + // with specific proposer_authority_required. + rpc Initialize(InitializeInput) returns (google.protobuf.Empty) { + } + + // Create an organization and return its address. + rpc CreateOrganization (CreateOrganizationInput) returns (aelf.Address) { + } + + // Batch approval proposal. + rpc ApproveMultiProposals(ProposalIdList) returns (google.protobuf.Empty){ + } + + // Creates an organization by system contract and return its address. + rpc CreateOrganizationBySystemContract(CreateOrganizationBySystemContractInput) returns (aelf.Address){ + } + + // Creates an organization to handle emergency events. + rpc CreateEmergencyResponseOrganization (google.protobuf.Empty) returns (google.protobuf.Empty) { + } + + // Get the organization according to the organization address. + rpc GetOrganization (aelf.Address) returns (Organization) { + option (aelf.is_view) = true; + } + + // Get the default organization address. + rpc GetDefaultOrganizationAddress (google.protobuf.Empty) returns (aelf.Address) { + option (aelf.is_view) = true; + } + + // Validates if the provided address is a parliament member. + rpc ValidateAddressIsParliamentMember(aelf.Address) returns (google.protobuf.BoolValue){ + option (aelf.is_view) = true; + } + + // Returns the list of whitelisted proposers. + rpc GetProposerWhiteList(google.protobuf.Empty) returns (acs3.ProposerWhiteList){ + option (aelf.is_view) = true; + } + + // Filter still pending ones not yet voted by the sender from provided proposals. + rpc GetNotVotedPendingProposals(ProposalIdList) returns (ProposalIdList){ + option (aelf.is_view) = true; + } + + // Filter not yet voted ones by the sender from provided proposals. + rpc GetNotVotedProposals(ProposalIdList) returns (ProposalIdList){ + option (aelf.is_view) = true; + } + + // Calculates with input and return the organization address. + rpc CalculateOrganizationAddress(CreateOrganizationInput) returns (aelf.Address){ + option (aelf.is_view) = true; + } + + rpc GetEmergencyResponseOrganizationAddress (google.protobuf.Empty) returns (aelf.Address) { + option (aelf.is_view) = true; + } +} + +message CreateOrganizationInput { + // The threshold for releasing the proposal. + acs3.ProposalReleaseThreshold proposal_release_threshold = 1; + // Setting this to false will allow anyone creating proposals. + bool proposer_authority_required = 2; + // Setting this to true can allow parliament member to create proposals. + bool parliament_member_proposing_allowed = 3; + // The creation token is for organization address generation. + aelf.Hash creation_token = 4; +} + +message Organization { + // Indicates if proposals need authority to be created. + bool proposer_authority_required = 1; + // The organization address. + aelf.Address organization_address = 2; + // The organization id. + aelf.Hash organization_hash = 3; + // The threshold for releasing the proposal. + acs3.ProposalReleaseThreshold proposal_release_threshold = 4; + // Indicates if parliament member can propose to this organization. + bool parliament_member_proposing_allowed = 5; + // The creation token is for organization address generation. + aelf.Hash creation_token = 6; +} + +message ProposalInfo { + // The proposal ID. + aelf.Hash proposal_id = 1; + // The method that this proposal will call when being released. + string contract_method_name = 2; + // The address of the target contract. + aelf.Address to_address = 3; + // The parameters of the release transaction. + bytes params = 4; + // The date at which this proposal will expire. + google.protobuf.Timestamp expired_time = 5; + // The address of the proposer of this proposal. + aelf.Address proposer = 6; + // The address of this proposals organization. + aelf.Address organization_address = 7; + // Address list of approved. + repeated aelf.Address approvals = 8; + // Address list of rejected. + repeated aelf.Address rejections = 9; + // Address list of abstained. + repeated aelf.Address abstentions = 10; + // Url is used for proposal describing. + string proposal_description_url = 11; +} + +message InitializeInput{ + // Privileged proposer would be the first address in parliament proposer whitelist. + aelf.Address privileged_proposer = 1; + // The setting indicates if proposals need authority to be created for first/default parliament organization. + bool proposer_authority_required = 2; +} + +message ProposalIdList{ + // The list of proposal ids. + repeated aelf.Hash proposal_ids = 1; +} + +message CreateOrganizationBySystemContractInput { + // The parameters of creating organization. + CreateOrganizationInput organization_creation_input = 1; + // The organization address callback method which replies the organization address to caller contract. + string organization_address_feedback_method = 2; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/profit_contract.proto b/src/AElf.Client.Protobuf/Protobuf/profit_contract.proto new file mode 100644 index 0000000..745406d --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/profit_contract.proto @@ -0,0 +1,370 @@ +/** + * Profit contract. + */ +syntax = "proto3"; + +package Profit; + +import "aelf/core.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; + +option csharp_namespace = "AElf.Contracts.Profit"; + +service ProfitContract { + option (aelf.csharp_state) = "AElf.Contracts.Profit.ProfitContractState"; + + // Create a scheme for profit distribution, and return the created scheme id. + rpc CreateScheme (CreateSchemeInput) returns (aelf.Hash) { + } + + // Add beneficiary to scheme. + rpc AddBeneficiary (AddBeneficiaryInput) returns (google.protobuf.Empty) { + } + + // Remove beneficiary from scheme. + rpc RemoveBeneficiary (RemoveBeneficiaryInput) returns (google.protobuf.Empty) { + } + + // Batch add beneficiary to scheme. + rpc AddBeneficiaries (AddBeneficiariesInput) returns (google.protobuf.Empty) { + } + + // Batch remove beneficiary from scheme. + rpc RemoveBeneficiaries (RemoveBeneficiariesInput) returns (google.protobuf.Empty) { + } + + rpc FixProfitDetail (FixProfitDetailInput) returns (google.protobuf.Empty) { + } + + // Contribute profit to a scheme. + rpc ContributeProfits (ContributeProfitsInput) returns (google.protobuf.Empty) { + } + + // The beneficiary draws tokens from the scheme. + rpc ClaimProfits (ClaimProfitsInput) returns (google.protobuf.Empty) { + } + + // Distribute profits to schemes, including its sub scheme according to period and token symbol, + // should be called by the manager. + rpc DistributeProfits (DistributeProfitsInput) returns (google.protobuf.Empty) { + } + + // Add sub scheme to a scheme. + // This will effectively add the specified sub-scheme as a beneficiary of the parent scheme. + rpc AddSubScheme (AddSubSchemeInput) returns (google.protobuf.Empty) { + } + + // Remove sub scheme from a scheme. + rpc RemoveSubScheme (RemoveSubSchemeInput) returns (google.protobuf.Empty) { + } + + // Reset the manager of a scheme. + rpc ResetManager (ResetManagerInput) returns (google.protobuf.Empty) { + } + + // Get all schemes managed by the specified manager. + rpc GetManagingSchemeIds (GetManagingSchemeIdsInput) returns (CreatedSchemeIds) { + option (aelf.is_view) = true; + } + + // Get scheme according to scheme id. + rpc GetScheme (aelf.Hash) returns (Scheme) { + option (aelf.is_view) = true; + } + + // Get the virtual address of the number of period of the scheme. + rpc GetSchemeAddress (SchemePeriod) returns (aelf.Address) { + option (aelf.is_view) = true; + } + + // Query the distributed profit information for the specified period. + rpc GetDistributedProfitsInfo (SchemePeriod) returns (DistributedProfitsInfo) { + option (aelf.is_view) = true; + } + + // Query the beneficiary's profit information on the scheme. + rpc GetProfitDetails (GetProfitDetailsInput) returns (ProfitDetails) { + option (aelf.is_view) = true; + } + + // Query the amount of profit according to token symbol. (up to 10 periods). + rpc GetProfitAmount (GetProfitAmountInput) returns (google.protobuf.Int64Value) { + option (aelf.is_view) = true; + } + + // Query all profit (up to 10 periods). + rpc GetProfitsMap (ClaimProfitsInput) returns (ReceivedProfitsMap) { + option (aelf.is_view) = true; + } +} + +message CreateSchemeInput { + // Period of profit distribution. + int64 profit_receiving_due_period_count = 1; + // Whether all the schemes balance will be distributed during distribution each period. + bool is_release_all_balance_every_time_by_default = 2; + // Delay distribute period. + int32 delay_distribute_period_count = 3; + // The manager of this scheme, the default is the creator. + aelf.Address manager = 4; + // Whether you can directly remove the beneficiary. + bool can_remove_beneficiary_directly = 5; + // Use to generate scheme id. + aelf.Hash token = 6; +} + +message Scheme { + // The virtual address of the scheme. + aelf.Address virtual_address = 1; + // The total weight of the scheme. + int64 total_shares = 2; + // The manager of the scheme. + aelf.Address manager = 3; + // The current period. + int64 current_period = 4; + // Sub schemes information. + repeated SchemeBeneficiaryShare sub_schemes = 5; + // Whether you can directly remove the beneficiary. + bool can_remove_beneficiary_directly = 6; + // Period of profit distribution. + int64 profit_receiving_due_period_count = 7; + // Whether all the schemes balance will be distributed during distribution each period. + bool is_release_all_balance_every_time_by_default = 8; + // The is of the scheme. + aelf.Hash scheme_id = 9; + // Delay distribute period. + int32 delay_distribute_period_count = 10; + // Record the scheme's current total share for deferred distribution of benefits, period -> total shares. + map cached_delay_total_shares = 11; + // The received token symbols. + repeated string received_token_symbols = 12; +} + +message SchemeBeneficiaryShare { + // The id of the sub scheme. + aelf.Hash scheme_id = 1; + // The weight of the sub scheme. + int64 shares = 2; +} + +message AddBeneficiaryInput { + // The scheme id. + aelf.Hash scheme_id = 1; + // The beneficiary information. + BeneficiaryShare beneficiary_share = 2; + // The end period which the beneficiary receives the profit. + int64 start_period = 3; + int64 end_period = 4; + bool is_fix_profit_detail = 5; + aelf.Hash profit_detail_id = 6; +} + +message FixProfitDetailInput { + aelf.Hash scheme_id = 1; + BeneficiaryShare beneficiary_share = 2; + int64 start_period = 3; + int64 end_period = 4; + aelf.Hash profit_detail_id = 5; +} + +message RemoveBeneficiaryInput { + // The address of beneficiary. + aelf.Address beneficiary = 1; + // The scheme id. + aelf.Hash scheme_id = 2; + aelf.Hash profit_detail_id = 3; +} + +message AddBeneficiariesInput { + // The scheme id. + aelf.Hash scheme_id = 1; + // The beneficiary information. + repeated BeneficiaryShare beneficiary_shares = 2; + // The end period which the beneficiary receives the profit. + int64 end_period = 3; +} + +message RemoveBeneficiariesInput { + // The addresses of beneficiary. + repeated aelf.Address beneficiaries = 1; + // The scheme id. + aelf.Hash scheme_id = 2; +} + +message BeneficiaryShare { + // The address of beneficiary. + aelf.Address beneficiary = 1; + // The profit weight of the beneficiary in the scheme. + int64 shares = 2; +} + +message ClaimProfitsInput { + // The scheme id. + aelf.Hash scheme_id = 1; + // The address of beneficiary. + aelf.Address beneficiary = 2; +} + +message DistributeProfitsInput { + // The scheme id to distribute. + aelf.Hash scheme_id = 1; + // The period number to distribute, should be the current period. + int64 period = 2; + // The amount to distribute, symbol -> amount. + map amounts_map = 3; +} + +message ProfitDetails { + // The profit information. + repeated ProfitDetail details = 1; +} + +message ProfitDetail { + // The start period number. + int64 start_period = 1; + // The end period number. + int64 end_period = 2; + // The weight of the proceeds on the current period of the scheme. + int64 shares = 3; + // The last period number that the beneficiary received the profit. + int64 last_profit_period = 4; + // Whether the weight has been removed. + bool is_weight_removed = 5; + aelf.Hash id = 6; +} + +message ContributeProfitsInput { + // The scheme id to contribute. + aelf.Hash scheme_id = 1; + // The amount to contribute. + int64 amount = 2; + // The number of periods in which the income is used for dividends. + int64 period = 3; + // The token symbol to contribute. + string symbol = 4; +} + +message AddSubSchemeInput { + // The parent scheme id. + aelf.Hash scheme_id = 1; + // The sub scheme id. + aelf.Hash sub_scheme_id = 2; + // The profit weight of sub scheme. + int64 sub_scheme_shares = 3; +} + +message RemoveSubSchemeInput { + // The parent scheme id. + aelf.Hash scheme_id = 1; + // The sub scheme id. + aelf.Hash sub_scheme_id = 2; +} + +message DistributedProfitsInfo { + // The total amount of shares in this scheme at the current period. + int64 total_shares = 1; + // The contributed amount in this scheme at the current period. + map amounts_map = 2;//Token symbol -> Amount + // Whether released. + bool is_released = 3; +} + +message CreatedSchemeIds { + // The scheme ids. + repeated aelf.Hash scheme_ids = 1; +} + +message GetManagingSchemeIdsInput { + // The manager address. + aelf.Address manager = 1; +} + +message SchemePeriod { + // The scheme id. + aelf.Hash scheme_id = 1; + // The period number. + int64 period = 2; +} + +message GetProfitDetailsInput { + // The scheme id. + aelf.Hash scheme_id = 1; + // The address of beneficiary. + aelf.Address beneficiary = 2; +} + +message ResetManagerInput { + // The scheme id. + aelf.Hash scheme_id = 1; + // The address of new manager. + aelf.Address new_manager = 2; +} + +message GetProfitAmountInput { + // The scheme id. + aelf.Hash scheme_id = 1; + // The token symbol. + string symbol = 2; + // The beneficiary's address. + aelf.Address beneficiary = 3; +} + +message ReceivedProfitsMap { + // The collection of profits received, token symbol -> amount. + map value = 1; +} + +message ReceivedProfitsMapList { + repeated ReceivedProfitsMap value = 1; +} + +message SchemeCreated { + option (aelf.is_event) = true; + // The virtual address of the created scheme. + aelf.Address virtual_address = 1; + // The manager of the created scheme. + aelf.Address manager = 2; + // Period of profit distribution. + int64 profit_receiving_due_period_count = 3; + // Whether all the schemes balance will be distributed during distribution each period. + bool is_release_all_balance_every_time_by_default = 4; + // The id of the created scheme. + aelf.Hash scheme_id = 5; +} + +message ProfitsClaimed { + option (aelf.is_event) = true; + // The beneficiary's address claimed. + aelf.Address beneficiary = 1; + // The token symbol claimed. + string symbol = 2; + // The amount claimed. + int64 amount = 3; + // The period number claimed. + int64 period = 4; + // The shares of the claimer. + int64 claimer_shares = 5; + // The total shares at the current period. + int64 total_shares = 6; +} + +message ProfitDetailAdded { + option (aelf.is_event) = true; + int64 start_period = 1; + int64 end_period = 2; + int64 shares = 3; + bool is_weight_removed = 4; + aelf.Address beneficiary = 5; +} + +message DistributedPeriodInfoChanged { + option (aelf.is_event) = true; + aelf.Hash scheme_id = 1; + int64 period = 2; + int64 total_shares = 3; + ReceivedProfitsMapList profits_map_list = 4; + bool is_released = 5; + aelf.Address virtual_address = 6; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/referendum_contract.proto b/src/AElf.Client.Protobuf/Protobuf/referendum_contract.proto new file mode 100644 index 0000000..82af016 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/referendum_contract.proto @@ -0,0 +1,129 @@ +/** + * Referendum contract. + */ +syntax = "proto3"; + +package Referendum; + +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "aelf/core.proto"; +import "acs3.proto"; + +option csharp_namespace = "AElf.Contracts.Referendum"; + +service ReferendumContract { + + option (aelf.csharp_state) = "AElf.Contracts.Referendum.ReferendumState"; + + // Unlock the token used for voting according to proposal id. + rpc ReclaimVoteToken (aelf.Hash) returns (google.protobuf.Empty) { + } + + // Create an organization and return its address. + rpc CreateOrganization (CreateOrganizationInput) returns (aelf.Address) { + } + + // Creates an organization by system contract and return its address. + rpc CreateOrganizationBySystemContract (CreateOrganizationBySystemContractInput) returns (aelf.Address) { + } + + // Get the organization according to the organization address. + rpc GetOrganization (aelf.Address) returns (Organization) { + option (aelf.is_view) = true; + } + + // Calculate the input and return the organization address. + rpc CalculateOrganizationAddress (CreateOrganizationInput) returns (aelf.Address) { + option (aelf.is_view) = true; + } + + // Get the virtual address of a proposal based on the proposal id. + rpc GetProposalVirtualAddress (aelf.Hash) returns (aelf.Address) { + } +} + +message CreateOrganizationInput { + // The token used during proposal operations. + string token_symbol = 1; + // The threshold for releasing the proposal. + acs3.ProposalReleaseThreshold proposal_release_threshold = 2; + // The proposer whitelist. + acs3.ProposerWhiteList proposer_white_list = 3; + // The creation token is for organization address generation. + aelf.Hash creation_token = 4; +} + +message Organization { + // The threshold for releasing the proposal. + acs3.ProposalReleaseThreshold proposal_release_threshold = 1; + // The token used during proposal operations. + string token_symbol = 2; + // The address of organization. + aelf.Address organization_address = 3; + // The organizations id. + aelf.Hash organization_hash = 4; + // The proposer whitelist. + acs3.ProposerWhiteList proposer_white_list = 5; + // The creation token is for organization address generation. + aelf.Hash creation_token = 6; +} + +message Receipt { + // The amount of token locked. + int64 amount = 1; + // The symbol of token locked. + string token_symbol = 2; + // The lock id. + aelf.Hash lock_id = 3; +} + +message ProposalInfo { + // The proposal ID. + aelf.Hash proposal_id = 1; + // The method that this proposal will call when being released. + string contract_method_name = 2; + // The address of the target contract. + aelf.Address to_address = 3; + // The parameters of the release transaction. + bytes params = 4; + // The date at which this proposal will expire. + google.protobuf.Timestamp expired_time = 5; + // The address of the proposer of this proposal. + aelf.Address proposer = 6; + // The address of this proposals organization. + aelf.Address organization_address = 7; + // The count of approved. + int64 approval_count = 8; + // The count of rejected. + int64 rejection_count = 9; + // The count of abstained. + int64 abstention_count = 10; + // Url is used for proposal describing. + string proposal_description_url = 11; +} + +message CreateOrganizationBySystemContractInput { + // The parameters of creating organization. + CreateOrganizationInput organization_creation_input = 1; + // The organization address callback method which replies the organization address to caller contract. + string organization_address_feedback_method = 2; +} + +message ReferendumReceiptCreated { + option (aelf.is_event) = true; + // The id of the proposal. + aelf.Hash proposal_id = 1; + // The sender address. + aelf.Address address = 2; + // The symbol of token locked. + string symbol = 3; + // The amount of token locked. + int64 amount = 4; + // The type of receipt(Approve, Reject or Abstain). + string receipt_type = 5; + // The timestamp of this method call. + google.protobuf.Timestamp time = 6; + // The address of the organization. + aelf.Address organization_address = 7 [(aelf.is_indexed) = true]; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/token_contract.proto b/src/AElf.Client.Protobuf/Protobuf/token_contract.proto new file mode 100644 index 0000000..93d1433 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/token_contract.proto @@ -0,0 +1,739 @@ +/** + * MultiToken contract. + */ +syntax = "proto3"; + +package token; + +import "aelf/core.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; + +option csharp_namespace = "AElf.Contracts.MultiToken"; + +service TokenContract { + // Create a new token. + rpc Create (CreateInput) returns (google.protobuf.Empty) { + } + + // Issuing some amount of tokens to an address is the action of increasing that addresses balance + // for the given token. The total amount of issued tokens must not exceed the total supply of the token + // and only the issuer (creator) of the token can issue tokens. + // Issuing tokens effectively increases the circulating supply. + rpc Issue (IssueInput) returns (google.protobuf.Empty) { + } + + // Transferring tokens simply is the action of transferring a given amount of tokens from one address to another. + // The origin or source address is the signer of the transaction. + // The balance of the sender must be higher than the amount that is transferred. + rpc Transfer (TransferInput) returns (google.protobuf.Empty) { + } + + // The TransferFrom action will transfer a specified amount of tokens from one address to another. + // For this operation to succeed the from address needs to have approved (see allowances) enough tokens + // to Sender of this transaction. If successful the amount will be removed from the allowance. + rpc TransferFrom (TransferFromInput) returns (google.protobuf.Empty) { + } + + // The approve action increases the allowance from the Sender to the Spender address, + // enabling the Spender to call TransferFrom. + rpc Approve (ApproveInput) returns (google.protobuf.Empty) { + } + + // This is the reverse operation for Approve, it will decrease the allowance. + rpc UnApprove (UnApproveInput) returns (google.protobuf.Empty) { + } + + // This method can be used to lock tokens. + rpc Lock (LockInput) returns (google.protobuf.Empty) { + } + + // This is the reverse operation of locking, it un-locks some previously locked tokens. + rpc Unlock (UnlockInput) returns (google.protobuf.Empty) { + } + + // This action will burn the specified amount of tokens, removing them from the token’s Supply. + rpc Burn (BurnInput) returns (google.protobuf.Empty) { + } + + // Change the issuer of the specified token. Only the original issuer can change it. + rpc ChangeTokenIssuer (ChangeTokenIssuerInput) returns (google.protobuf.Empty) { + } + + // Set the primary token of side chain. + rpc SetPrimaryTokenSymbol (SetPrimaryTokenSymbolInput) returns (google.protobuf.Empty) { + } + + // This interface is used for cross-chain transfer. + rpc CrossChainTransfer (CrossChainTransferInput) returns (google.protobuf.Empty) { + } + + // This method is used to receive cross-chain transfers. + rpc CrossChainReceiveToken (CrossChainReceiveTokenInput) returns (google.protobuf.Empty) { + } + + // The side chain creates tokens. + rpc CrossChainCreateToken(CrossChainCreateTokenInput) returns (google.protobuf.Empty) { + } + + // When the side chain is started, the side chain is initialized with the parent chain information. + rpc InitializeFromParentChain (InitializeFromParentChainInput) returns (google.protobuf.Empty) { + } + + // Handle the transaction fees charged by ChargeTransactionFees. + rpc ClaimTransactionFees (TotalTransactionFeesMap) returns (google.protobuf.Empty) { + } + + // Used to collect transaction fees. + rpc ChargeTransactionFees (ChargeTransactionFeesInput) returns (ChargeTransactionFeesOutput) { + } + + // Check the token threshold. + rpc CheckThreshold (CheckThresholdInput) returns (google.protobuf.Empty) { + } + + // Initialize coefficients of every type of tokens supporting charging fee. + rpc InitialCoefficients (google.protobuf.Empty) returns (google.protobuf.Empty){ + } + + // Processing resource token received. + rpc DonateResourceToken (TotalResourceTokensMaps) returns (google.protobuf.Empty) { + } + + // A transaction resource fee is charged to implement the ACS8 standards. + rpc ChargeResourceToken (ChargeResourceTokenInput) returns (google.protobuf.Empty) { + } + + // Verify that the resource token are sufficient. + rpc CheckResourceToken (google.protobuf.Empty) returns (google.protobuf.Empty) { + } + + // Set the list of tokens to pay transaction fees. + rpc SetSymbolsToPayTxSizeFee (SymbolListToPayTxSizeFee) returns (google.protobuf.Empty){ + } + + // Update the coefficient of the transaction fee calculation formula. + rpc UpdateCoefficientsForSender (UpdateCoefficientsInput) returns (google.protobuf.Empty) { + } + + // Update the coefficient of the transaction fee calculation formula. + rpc UpdateCoefficientsForContract (UpdateCoefficientsInput) returns (google.protobuf.Empty) { + } + + // This method is used to initialize the governance organization for some functions, + // including: the coefficient of the user transaction fee calculation formula, + // the coefficient of the contract developer resource fee calculation formula, and the side chain rental fee. + rpc InitializeAuthorizedController(google.protobuf.Empty) returns (google.protobuf.Empty){ + } + + // Query token information. + rpc GetTokenInfo (GetTokenInfoInput) returns (TokenInfo) { + option (aelf.is_view) = true; + } + + // Query native token information. + rpc GetNativeTokenInfo (google.protobuf.Empty) returns (TokenInfo) { + option (aelf.is_view) = true; + } + + // Query resource token information. + rpc GetResourceTokenInfo (google.protobuf.Empty) returns (TokenInfoList) { + option (aelf.is_view) = true; + } + + // Query the balance at the specified address. + rpc GetBalance (GetBalanceInput) returns (GetBalanceOutput) { + option (aelf.is_view) = true; + } + + // Query the account's allowance for other addresses + rpc GetAllowance (GetAllowanceInput) returns (GetAllowanceOutput) { + option (aelf.is_view) = true; + } + + // Check whether the token is in the whitelist of an address, + // which can be called TransferFrom to transfer the token under the condition of not being credited. + rpc IsInWhiteList (IsInWhiteListInput) returns (google.protobuf.BoolValue) { + option (aelf.is_view) = true; + } + + // Query the information for a lock. + rpc GetLockedAmount (GetLockedAmountInput) returns (GetLockedAmountOutput) { + option (aelf.is_view) = true; + } + + // Query the address of receiving token in cross-chain transfer. + rpc GetCrossChainTransferTokenContractAddress (GetCrossChainTransferTokenContractAddressInput) returns (aelf.Address) { + option (aelf.is_view) = true; + } + + // Query the name of the primary Token. + rpc GetPrimaryTokenSymbol (google.protobuf.Empty) returns (google.protobuf.StringValue) { + option (aelf.is_view) = true; + } + + // Query the coefficient of the transaction fee calculation formula. + rpc GetCalculateFeeCoefficientsForContract (google.protobuf.Int32Value) returns (CalculateFeeCoefficients) { + option (aelf.is_view) = true; + } + + // Query the coefficient of the transaction fee calculation formula. + rpc GetCalculateFeeCoefficientsForSender (google.protobuf.Empty) returns (CalculateFeeCoefficients) { + option (aelf.is_view) = true; + } + + // Query tokens that can pay transaction fees. + rpc GetSymbolsToPayTxSizeFee (google.protobuf.Empty) returns (SymbolListToPayTxSizeFee){ + option (aelf.is_view) = true; + } + + // Query the hash of the last input of ClaimTransactionFees. + rpc GetLatestTotalTransactionFeesMapHash (google.protobuf.Empty) returns (aelf.Hash){ + option (aelf.is_view) = true; + } + + // Query the hash of the last input of DonateResourceToken. + rpc GetLatestTotalResourceTokensMapsHash (google.protobuf.Empty) returns (aelf.Hash){ + option (aelf.is_view) = true; + } + rpc IsTokenAvailableForMethodFee (google.protobuf.StringValue) returns (google.protobuf.BoolValue) { + option (aelf.is_view) = true; + } +} + +message TokenInfo { + // The symbol of the token.f + string symbol = 1; + // The full name of the token. + string token_name = 2; + // The current supply of the token. + int64 supply = 3; + // The total supply of the token. + int64 total_supply = 4; + // The precision of the token. + int32 decimals = 5; + // The address that created the token. + aelf.Address issuer = 6; + // A flag indicating if this token is burnable. + bool is_burnable = 7; + // The chain id of the token. + int32 issue_chain_id = 8; + // The amount of issued tokens. + int64 issued = 9; +} + +message CreateInput { + // The symbol of the token. + string symbol = 1; + // The full name of the token. + string token_name = 2; + // The total supply of the token. + int64 total_supply = 3; + // The precision of the token + int32 decimals = 4; + // The address that created the token. + aelf.Address issuer = 5; + // A flag indicating if this token is burnable. + bool is_burnable = 6; + // A whitelist address list used to lock tokens. + repeated aelf.Address lock_white_list = 7; + // The chain id of the token. + int32 issue_chain_id = 8; +} + +message SetPrimaryTokenSymbolInput { + // The symbol of the token. + string symbol = 1; +} + +message IssueInput { + // The token symbol to issue. + string symbol = 1; + // The token amount to issue. + int64 amount = 2; + // The memo. + string memo = 3; + // The target address to issue. + aelf.Address to = 4; +} + +message TransferInput { + // The receiver of the token. + aelf.Address to = 1; + // The token symbol to transfer. + string symbol = 2; + // The amount to to transfer. + int64 amount = 3; + // The memo. + string memo = 4; +} + +message LockInput { + // The one want to lock his token. + aelf.Address address = 1; + // Id of the lock. + aelf.Hash lock_id = 2; + // The symbol of the token to lock. + string symbol = 3; + // a memo. + string usage = 4; + // The amount of tokens to lock. + int64 amount = 5; +} + +message UnlockInput { + // The one want to un-lock his token. + aelf.Address address = 1; + // Id of the lock. + aelf.Hash lock_id = 2; + // The symbol of the token to un-lock. + string symbol = 3; + // a memo. + string usage = 4; + // The amount of tokens to un-lock. + int64 amount = 5; +} + +message TransferFromInput { + // The source address of the token. + aelf.Address from = 1; + // The destination address of the token. + aelf.Address to = 2; + // The symbol of the token to transfer. + string symbol = 3; + // The amount to transfer. + int64 amount = 4; + // The memo. + string memo = 5; +} + +message ApproveInput { + // The address that allowance will be increased. + aelf.Address spender = 1; + // The symbol of token to approve. + string symbol = 2; + // The amount of token to approve. + int64 amount = 3; +} + +message UnApproveInput { + // The address that allowance will be decreased. + aelf.Address spender = 1; + // The symbol of token to un-approve. + string symbol = 2; + // The amount of token to un-approve. + int64 amount = 3; +} + +message BurnInput { + // The symbol of token to burn. + string symbol = 1; + // The amount of token to burn. + int64 amount = 2; +} + +message ChargeResourceTokenInput { + // Collection of charge resource token, Symbol->Amount. + map cost_dic = 1; + // The sender of the transaction. + aelf.Address caller = 2; +} + +message TransactionFeeBill { + // The transaction fee dictionary, Symbol->fee. + map fees_map = 1; +} + +message CheckThresholdInput { + // The sender of the transaction. + aelf.Address sender = 1; + // The threshold to set, Symbol->Threshold. + map symbol_to_threshold = 2; + // Whether to check the allowance. + bool is_check_allowance = 3; +} + +message GetTokenInfoInput { + // The symbol of token. + string symbol = 1; +} + +message GetBalanceInput { + // The symbol of token. + string symbol = 1; + // The target address of the query. + aelf.Address owner = 2; +} + +message GetBalanceOutput { + // The symbol of token. + string symbol = 1; + // The target address of the query. + aelf.Address owner = 2; + // The balance of the owner. + int64 balance = 3; +} + +message GetAllowanceInput { + // The symbol of token. + string symbol = 1; + // The address of the token owner. + aelf.Address owner = 2; + // The address of the spender. + aelf.Address spender = 3; +} + +message GetAllowanceOutput { + // The symbol of token. + string symbol = 1; + // The address of the token owner. + aelf.Address owner = 2; + // The address of the spender. + aelf.Address spender = 3; + // The amount of allowance. + int64 allowance = 4; +} + +message CrossChainTransferInput { + // The receiver of transfer. + aelf.Address to = 1; + // The symbol of token. + string symbol = 2; + // The amount of token to transfer. + int64 amount = 3; + // The memo. + string memo = 4; + // The destination chain id. + int32 to_chain_id = 5; + // The chain id of the token. + int32 issue_chain_id = 6; +} + +message CrossChainReceiveTokenInput { + // The source chain id. + int32 from_chain_id = 1; + // The height of the transfer transaction. + int64 parent_chain_height = 2; + // The raw bytes of the transfer transaction. + bytes transfer_transaction_bytes = 3; + // The merkle path created from the transfer transaction. + aelf.MerklePath merkle_path = 4; +} + +message IsInWhiteListInput { + // The symbol of token. + string symbol = 1; + // The address to check. + aelf.Address address = 2; +} + +message SymbolToPayTxSizeFee{ + // The symbol of token. + string token_symbol = 1; + // The charge weight of primary token. + int32 base_token_weight = 2; + // The new added token charge weight. For example, the charge weight of primary Token is set to 1. + // The newly added token charge weight is set to 10. If the transaction requires 1 unit of primary token, + // the user can also pay for 10 newly added tokens. + int32 added_token_weight = 3; +} + +message SymbolListToPayTxSizeFee{ + // Transaction fee token information. + repeated SymbolToPayTxSizeFee symbols_to_pay_tx_size_fee = 1; +} + +message ChargeTransactionFeesInput { + // The method name of transaction. + string method_name = 1; + // The contract address of transaction. + aelf.Address contract_address = 2; + // The amount of transaction size fee. + int64 transaction_size_fee = 3; + // Transaction fee token information. + repeated SymbolToPayTxSizeFee symbols_to_pay_tx_size_fee = 4; +} + +message ChargeTransactionFeesOutput { + // Whether the charge was successful. + bool success = 1; + // The charging information. + string charging_information = 2; +} + +message ExtraTokenListModified { + option (aelf.is_event) = true; + // Transaction fee token information. + SymbolListToPayTxSizeFee symbol_list_to_pay_tx_size_fee = 1; +} + +message GetLockedAmountInput { + // The address of the lock. + aelf.Address address = 1; + // The token symbol. + string symbol = 2; + // The id of the lock. + aelf.Hash lock_id = 3; +} + +message GetLockedAmountOutput { + // The address of the lock. + aelf.Address address = 1; + // The token symbol. + string symbol = 2; + // The id of the lock. + aelf.Hash lock_id = 3; + // The locked amount. + int64 amount = 4; +} + +message TokenInfoList { + // List of token information. + repeated TokenInfo value = 1; +} + +message GetCrossChainTransferTokenContractAddressInput { + // The chain id. + int32 chainId = 1; +} + +message CrossChainCreateTokenInput { + // The chain id of the chain on which the token was created. + int32 from_chain_id = 1; + // The height of the transaction that created the token. + int64 parent_chain_height = 2; + // The transaction that created the token. + bytes transaction_bytes = 3; + // The merkle path created from the transaction that created the transaction. + aelf.MerklePath merkle_path = 4; +} + +message InitializeFromParentChainInput { + // The amount of resource. + map resource_amount = 1; + // The token contract addresses. + map registered_other_token_contract_addresses = 2; + // The creator the side chain. + aelf.Address creator = 3; +} + +message UpdateCoefficientsInput { + // The specify pieces gonna update. + repeated int32 piece_numbers = 1; + // Coefficients of one single type. + CalculateFeeCoefficients coefficients = 2; +} + +enum FeeTypeEnum { + READ = 0; + STORAGE = 1; + WRITE = 2; + TRAFFIC = 3; + TX = 4; +} + +message CalculateFeePieceCoefficients { + // Coefficients of one single piece. + // The first char is its type: liner / power. + // The second char is its piece upper bound. + repeated int32 value = 1; +} + +message CalculateFeeCoefficients { + // The resource fee type, like READ, WRITE, etc. + int32 fee_token_type = 1; + // Coefficients of one single piece. + repeated CalculateFeePieceCoefficients piece_coefficients_list = 2; +} + +message AllCalculateFeeCoefficients { + // The coefficients of fee Calculation. + repeated CalculateFeeCoefficients value = 1; +} + +message TotalTransactionFeesMap +{ + // Token dictionary that charge transaction fee, Symbol->Amount. + map value = 1; + // The hash of the block processing the transaction. + aelf.Hash block_hash = 2; + // The height of the block processing the transaction. + int64 block_height = 3; +} + +message TotalResourceTokensMaps { + // Resource tokens to charge. + repeated ContractTotalResourceTokens value = 1; + // The hash of the block processing the transaction. + aelf.Hash block_hash = 2; + // The height of the block processing the transaction. + int64 block_height = 3; +} + +message ContractTotalResourceTokens { + // The contract address. + aelf.Address contract_address = 1; + // Resource tokens to charge. + TotalResourceTokensMap tokens_map = 2; +} + +message TotalResourceTokensMap +{ + // Resource token dictionary, Symbol->Amount. + map value = 1; +} + +message ChangeTokenIssuerInput +{ + // The token symbol. + string symbol = 1; + // The new token issuer for change. + aelf.Address new_token_Issuer = 2; +} + +message Transferred { + option (aelf.is_event) = true; + // The source address of the transferred token. + aelf.Address from = 1 [(aelf.is_indexed) = true]; + // The destination address of the transferred token. + aelf.Address to = 2 [(aelf.is_indexed) = true]; + // The symbol of the transferred token. + string symbol = 3 [(aelf.is_indexed) = true]; + // The amount of the transferred token. + int64 amount = 4; + // The memo. + string memo = 5; +} + +message Approved { + option (aelf.is_event) = true; + // The address of the token owner. + aelf.Address owner = 1 [(aelf.is_indexed) = true]; + // The address that allowance be increased. + aelf.Address spender = 2 [(aelf.is_indexed) = true]; + // The symbol of approved token. + string symbol = 3 [(aelf.is_indexed) = true]; + // The amount of approved token. + int64 amount = 4; +} + +message UnApproved { + option (aelf.is_event) = true; + // The address of the token owner. + aelf.Address owner = 1 [(aelf.is_indexed) = true]; + // The address that allowance be decreased. + aelf.Address spender = 2 [(aelf.is_indexed) = true]; + // The symbol of un-approved token. + string symbol = 3 [(aelf.is_indexed) = true]; + // The amount of un-approved token. + int64 amount = 4; +} + +message Burned +{ + option (aelf.is_event) = true; + // The address who wants to burn token. + aelf.Address burner = 1 [(aelf.is_indexed) = true]; + // The symbol of burned token. + string symbol = 2 [(aelf.is_indexed) = true]; + // The amount of burned token. + int64 amount = 3; +} + +message ChainPrimaryTokenSymbolSet { + option (aelf.is_event) = true; + // The symbol of token. + string token_symbol = 1; +} + + +message CalculateFeeAlgorithmUpdated { + option (aelf.is_event) = true; + // All calculate fee coefficients after modification. + AllCalculateFeeCoefficients all_type_fee_coefficients = 1; +} + +message RentalCharged { + option (aelf.is_event) = true; + // The symbol of rental fee charged. + string symbol = 1; + // The amount of rental fee charged. + int64 amount = 2; +} + +message RentalAccountBalanceInsufficient { + option (aelf.is_event) = true; + // The symbol of insufficient rental account balance. + string symbol = 1; + // The balance of the account. + int64 amount = 2; +} + +message TokenCreated { + option (aelf.is_event) = true; + // The symbol of the token. + string symbol = 1; + // The full name of the token. + string token_name = 2; + // The total supply of the token. + int64 total_supply = 3; + // The precision of the token. + int32 decimals = 4; + // The address that created the token. + aelf.Address issuer = 5; + // A flag indicating if this token is burnable. + bool is_burnable = 6; + // The chain id of the token. + int32 issue_chain_id = 7; +} + +message Issued { + option (aelf.is_event) = true; + // The symbol of issued token. + string symbol = 1; + // The amount of issued token. + int64 amount = 2; + // The memo. + string memo = 3; + // The issued target address. + aelf.Address to = 4; +} + +message CrossChainTransferred { + option (aelf.is_event) = true; + // The source address of the transferred token. + aelf.Address from = 1; + // The destination address of the transferred token. + aelf.Address to = 2; + // The symbol of the transferred token. + string symbol = 3; + // The amount of the transferred token. + int64 amount = 4; + // The memo. + string memo = 5; + // The destination chain id. + int32 to_chain_id = 6; + // The chain id of the token. + int32 issue_chain_id = 7; +} + +message CrossChainReceived { + option (aelf.is_event) = true; + // The source address of the transferred token. + aelf.Address from = 1; + // The destination address of the transferred token. + aelf.Address to = 2; + // The symbol of the received token. + string symbol = 3; + // The amount of the received token. + int64 amount = 4; + // The memo. + string memo = 5; + // The destination chain id. + int32 from_chain_id = 6; + // The chain id of the token. + int32 issue_chain_id = 7; + // The parent chain height of the transfer transaction. + int64 parent_chain_height = 8; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/token_converter_contract.proto b/src/AElf.Client.Protobuf/Protobuf/token_converter_contract.proto new file mode 100644 index 0000000..af6e99c --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/token_converter_contract.proto @@ -0,0 +1,193 @@ +/** + * TokenConvert contract. + */ +syntax = "proto3"; + +package TokenConverter; + +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "aelf/core.proto"; +import "authority_info.proto"; + +option csharp_namespace = "AElf.Contracts.TokenConverter"; + +service TokenConverterContract { + + option (aelf.csharp_state) = "AElf.Contracts.TokenConverter.TokenConverterContractState"; + + // Initialize TokenConvert contract. + rpc Initialize (InitializeInput) returns (google.protobuf.Empty) { + } + + rpc SetConnector (Connector) returns (google.protobuf.Empty) { + } + + // After establishing bancor model of token and base token, you can buy token through this method. + rpc Buy (BuyInput) returns (google.protobuf.Empty) { + } + + // After establishing bancor model of token and base token, you can sell token through this method. + rpc Sell (SellInput) returns (google.protobuf.Empty) { + } + + // Set the fee rate for buy/sell (fee amount = cost * feeRate). + rpc SetFeeRate (google.protobuf.StringValue) returns (google.protobuf.Empty) { + } + + // Before calling the EnableConnector, the connector controller can update the pair connector through this method. + rpc UpdateConnector(Connector) returns (google.protobuf.Empty){ + } + + // Add a pair connector for new token and the base token. + rpc AddPairConnector(PairConnectorParam) returns (google.protobuf.Empty){ + } + + // After adding a pair, you need to call this method to enable it before buy and sell token. + rpc EnableConnector (ToBeConnectedTokenInfo) returns (google.protobuf.Empty) { + } + + // Set the governance authority information for TokenConvert contract. + rpc ChangeConnectorController (AuthorityInfo) returns (google.protobuf.Empty) { + } + + // Query the pair connector according to token symbol. + rpc GetPairConnector (TokenSymbol) returns (PairConnector) { + option (aelf.is_view) = true; + } + + // Query the fee rate for buy/sell. + rpc GetFeeRate (google.protobuf.Empty) returns (google.protobuf.StringValue) { + option (aelf.is_view) = true; + } + + // Query the symbol of base token. + rpc GetBaseTokenSymbol (google.protobuf.Empty) returns (TokenSymbol) { + option (aelf.is_view) = true; + } + + // Query how much the base token need be deposited before enabling the connector. + rpc GetNeededDeposit(ToBeConnectedTokenInfo) returns (DepositInfo) { + option (aelf.is_view) = true; + } + + // Query how much the base token have been deposited. + rpc GetDepositConnectorBalance(google.protobuf.StringValue) returns (google.protobuf.Int64Value){ + option (aelf.is_view) = true; + } + + // Query the governance authority information for TokenConvert contract. + rpc GetControllerForManageConnector (google.protobuf.Empty) returns (AuthorityInfo) { + option (aelf.is_view) = true; + } + + // Query whether the token can be sold. + rpc IsSymbolAbleToSell (google.protobuf.StringValue) returns (google.protobuf.BoolValue) { + option (aelf.is_view) = true; + } +} + +message Connector { + // The token symbol. + string symbol = 1; + // The virtual balance for base token. + int64 virtual_balance = 2; + // The calculated weight value for this Connector. + string weight = 3; + // Whether to use Virtual Balance. + bool is_virtual_balance_enabled = 4; + // Whether the connector is enabled. + bool is_purchase_enabled = 5; + // Indicates its related connector, the pair connector includes a new created token connector and the base token connector. + string related_symbol = 6; + // Indicates if the connector is base token connector. + bool is_deposit_account = 7; +} + +message TokenSymbol { + // The token symbol. + string symbol = 1; +} + +message InitializeInput { + // Base token symbol, default is the native token symbol. + string base_token_symbol = 1; + // The fee rate for buy/sell. + string fee_rate = 2; + // The default added connectors. + repeated Connector connectors = 3; +} + +message BuyInput { + // The token symbol you want to buy. + string symbol = 1; + // The amount you want to buy. + int64 amount = 2; + // Limit of cost. If the token required for buy exceeds this value, the buy will be abandoned. + // And 0 is no limit. + int64 pay_limit = 3; +} + +message SellInput { + // The token symbol you want to sell. + string symbol = 1; + // The amount you want to sell. + int64 amount = 2; + // Limits on tokens obtained by selling. If the token obtained is less than this value, the sale will be abandoned. + // And 0 is no limit. + int64 receive_limit = 3; +} + +message TokenBought { + option (aelf.is_event) = true; + // The token symbol bought. + string symbol = 1 [(aelf.is_indexed) = true]; + // The amount bought. + int64 bought_amount = 2; + // The total cost of the base token. + int64 base_amount = 3; + // The fee amount. + int64 fee_amount =4; +} + +message TokenSold { + option (aelf.is_event) = true; + // The token symbol sold. + string symbol = 1 [(aelf.is_indexed) = true]; + // The amount sold. + int64 sold_amount = 2; + // The total received of the base token. + int64 base_amount = 3; + // The fee amount. + int64 fee_amount =4; +} +message PairConnectorParam { + // The token symbol. + string resource_connector_symbol = 1; + // The weight value of this token in the Bancor model. + string resource_weight = 2; + // This token corresponds to the value of base token. + int64 native_virtual_balance = 3; + // The weight value of base token in Bancor model. + string native_weight = 4; +} + +message ToBeConnectedTokenInfo{ + // The token symbol. + string token_symbol = 1; + // Specifies the number of tokens to convert to the TokenConvert contract. + int64 amount_to_token_convert = 2; +} +message DepositInfo{ + // How much more base Token is needed as the deposit. + int64 need_amount = 1; + // How many tokens are not on the TokenConvert address. + int64 amount_out_of_token_convert = 2; +} +message PairConnector{ + // The connector of the specified token. + Connector resource_connector = 1; + // The related connector. + Connector deposit_connector = 2; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/token_holder_contract.proto b/src/AElf.Client.Protobuf/Protobuf/token_holder_contract.proto new file mode 100644 index 0000000..53fd16c --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/token_holder_contract.proto @@ -0,0 +1,132 @@ +/** + * TokenHolder contract. + */ +syntax = "proto3"; + +package TokenHolder; + +import "aelf/core.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; + +option csharp_namespace = "AElf.Contracts.TokenHolder"; + +service TokenHolderContract { + + option (aelf.csharp_state) = "AElf.Contracts.TokenHolder.TokenHolderContractState"; + + // Create a scheme for distributing bonus. + rpc CreateScheme (CreateTokenHolderProfitSchemeInput) returns (google.protobuf.Empty) { + } + + // Add a beneficiary to a scheme. + rpc AddBeneficiary (AddTokenHolderBeneficiaryInput) returns (google.protobuf.Empty) { + } + + // Removes a beneficiary from a scheme. + // Note: amount > 0: update the weight of the beneficiary, amount = 0: remove the beneficiary. + rpc RemoveBeneficiary (RemoveTokenHolderBeneficiaryInput) returns (google.protobuf.Empty) { + } + + // Contribute profit to a scheme. + rpc ContributeProfits (ContributeProfitsInput) returns (google.protobuf.Empty) { + } + + // To distribute the profits of the scheme, the stakeholders of the project may go to receive dividends. + rpc DistributeProfits (DistributeProfitsInput) returns (google.protobuf.Empty) { + } + + // The user registers a bonus project. + rpc RegisterForProfits (RegisterForProfitsInput) returns (google.protobuf.Empty) { + } + + // After the lockup time expires, the user can withdraw token. + rpc Withdraw (aelf.Address) returns (google.protobuf.Empty) { + } + + // After DistributeProfits the holder can get his dividend. + rpc ClaimProfits (ClaimProfitsInput) returns (google.protobuf.Empty) { + } + + // Query the details of the specified scheme. + rpc GetScheme (aelf.Address) returns (TokenHolderProfitScheme) { + option (aelf.is_view) = true; + } + + // Query the dividends available to the holder. + rpc GetProfitsMap (ClaimProfitsInput) returns (ReceivedProfitsMap) { + option (aelf.is_view) = true; + } +} + +message CreateTokenHolderProfitSchemeInput { + // The token symbol. + string symbol = 1; + // Minimum lock time for holding token. + int64 minimum_lock_minutes = 2; + // Threshold setting for releasing dividends. + map auto_distribute_threshold = 3; +} + +message AddTokenHolderBeneficiaryInput { + // Beneficiary's address. + aelf.Address beneficiary = 1; + // The weight of the beneficiary's dividends in the scheme. + int64 shares = 2; +} + +message RemoveTokenHolderBeneficiaryInput { + // Beneficiary's address. + aelf.Address beneficiary = 1; + // The amount of weights to remove. + int64 amount = 2; +} + +message ContributeProfitsInput { + // The manager of the scheme. + aelf.Address scheme_manager = 1; + // The amount of token to contribute. + int64 amount = 2; + // The symbol of token to contribute. + string symbol = 3; +} + +message DistributeProfitsInput { + // The manager of the scheme. + aelf.Address scheme_manager = 1; + // The token to distribute, symbol -> amount. + map amounts_map = 2; +} + +message RegisterForProfitsInput { + // The manager of the scheme. + aelf.Address scheme_manager = 1; + // The amount of token holding. + int64 amount = 2; +} + +message ClaimProfitsInput { + // The manager of the scheme. + aelf.Address scheme_manager = 1; + // Beneficiary's address. + aelf.Address beneficiary = 2; +} + +message TokenHolderProfitScheme { + // The token symbol. + string symbol = 1; + // The scheme id. + aelf.Hash scheme_id = 2; + // The current dividend period. + int64 period = 3; + // Minimum lock time for holding token. + int64 minimum_lock_minutes = 4; + // Threshold setting for releasing dividends. + map auto_distribute_threshold = 5; +} + +message ReceivedProfitsMap { + // The amount of token the beneficiary can get, symbol -> amount. + map value = 1; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/transaction_fee.proto b/src/AElf.Client.Protobuf/Protobuf/transaction_fee.proto new file mode 100644 index 0000000..ed4ed8b --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/transaction_fee.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; + +package aelf; + +import "aelf/core.proto"; +import "aelf/options.proto"; + +option csharp_namespace = "AElf.Contracts.MultiToken"; + +service TransactionFee { +} + +// Messages + +message TransactionSizeFeeSymbols +{ + repeated TransactionSizeFeeSymbol transaction_size_fee_symbol_list = 1; +} + +message TransactionSizeFeeSymbol +{ + string token_symbol = 1; + int32 base_token_weight = 2; + int32 added_token_weight = 3; +} + +// Events + +message TransactionFeeCharged { + option (aelf.is_event) = true; + string symbol = 1; + int64 amount = 2; +} + +message ResourceTokenCharged { + option (aelf.is_event) = true; + string symbol = 1; + int64 amount = 2; + aelf.Address contract_address = 3; +} + +message ResourceTokenOwned { + option (aelf.is_event) = true; + string symbol = 1; + int64 amount = 2; + aelf.Address contract_address = 3; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/treasury_contract.proto b/src/AElf.Client.Protobuf/Protobuf/treasury_contract.proto new file mode 100644 index 0000000..0ce87cf --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/treasury_contract.proto @@ -0,0 +1,149 @@ +/** + * Treasury contract. + */ +syntax = "proto3"; + +package Treasury; + +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "aelf/core.proto"; +import "authority_info.proto"; + +option csharp_namespace = "AElf.Contracts.Treasury"; + +service TreasuryContract { + option (aelf.csharp_state) = "AElf.Contracts.Treasury.TreasuryContractState"; + + // Initialize treasury contract. + rpc InitialTreasuryContract (google.protobuf.Empty) returns (google.protobuf.Empty) { + } + + // Initialize the sub-item of the bonus scheme. + rpc InitialMiningRewardProfitItem (google.protobuf.Empty) returns (google.protobuf.Empty) { + } + + // Donate all tokens owned by the sender. + rpc DonateAll (DonateAllInput) returns (google.protobuf.Empty) { + } + + // Set the dividend weight of the sub-item of the dividend item. + rpc SetDividendPoolWeightSetting (DividendPoolWeightSetting) returns (google.protobuf.Empty){ + } + + // Set the miner reward weight. + rpc SetMinerRewardWeightSetting (MinerRewardWeightSetting) returns (google.protobuf.Empty){ + } + + // Set the reward for mining. + rpc UpdateMiningReward (google.protobuf.Int64Value) returns (google.protobuf.Empty){ + } + + // Change the governance authority information for treasury contract. + rpc ChangeTreasuryController (AuthorityInfo) returns (google.protobuf.Empty) { + } + + // AEDPoS Contract can notify Treasury Contract to aware miner replacement happened. + rpc RecordMinerReplacement (RecordMinerReplacementInput) returns (google.protobuf.Empty) { + } + + // Used to estimate the revenue weight of 10000 tokens voted by users. + rpc GetWelfareRewardAmountSample (GetWelfareRewardAmountSampleInput) returns (GetWelfareRewardAmountSampleOutput) { + option (aelf.is_view) = true; + } + + // Get the scheme id of treasury. + rpc GetTreasurySchemeId (google.protobuf.Empty) returns (aelf.Hash) { + option (aelf.is_view) = true; + } + + // Query the weight percentage of dividend pool items. + rpc GetDividendPoolWeightProportion (google.protobuf.Empty) returns (DividendPoolWeightProportion) { + option (aelf.is_view) = true; + } + + // Query the weight percentage of the dividend item for miner. + rpc GetMinerRewardWeightProportion (google.protobuf.Empty) returns (MinerRewardWeightProportion) { + option (aelf.is_view) = true; + } + + // Query the governance authority information. + rpc GetTreasuryController (google.protobuf.Empty) returns (AuthorityInfo) { + option (aelf.is_view) = true; + } +} + +message GetWelfareRewardAmountSampleInput { + // Token lock time. + repeated int64 value = 1; +} + +message GetWelfareRewardAmountSampleOutput { + // The weight calculated. + repeated int64 value = 1; +} + +message DonateAllInput { + // The token symbol to donate. + string symbol = 1; +} + +message MinerReElectionInformation { + // The reappointment information for miner. + map continual_appointment_times = 1; +} + +message DividendPoolWeightSetting { + // The dividend weight for citizen. + int32 citizen_welfare_weight = 1; + // The dividend weight for backup nodes. + int32 backup_subsidy_weight = 2; + // The dividend weight for miners. + int32 miner_reward_weight = 3; +} + +message MinerRewardWeightSetting { + // The dividend weight for all current miners. + int32 basic_miner_reward_weight = 1; + // The dividend weight for new miners. + int32 welcome_reward_weight = 2; + // The dividend weight for the flexible scheme. + int32 flexible_reward_weight = 3; +} + +message SchemeProportionInfo { + // The scheme id. + aelf.Hash scheme_id = 1; + // Dividend weight percentage. + int32 proportion = 2; +} + +message DividendPoolWeightProportion { + // The proportion of citizen welfare. + SchemeProportionInfo citizen_welfare_proportion_info = 1; + // The proportion of candidate nodes. + SchemeProportionInfo backup_subsidy_proportion_info = 2; + // The proportion of miner + SchemeProportionInfo miner_reward_proportion_info = 3; +} + +message MinerRewardWeightProportion { + // The proportion of the basic income of the miner. + SchemeProportionInfo basic_miner_reward_proportion_info = 1; + // The proportion of the vote of the miner. + SchemeProportionInfo welcome_reward_proportion_info = 2; + // The proportion of the reappointment of the miner. + SchemeProportionInfo flexible_reward_proportion_info = 3; +} + +message RecordMinerReplacementInput { + string old_pubkey = 1; + string new_pubkey = 2; + int64 current_term_number = 3; + bool is_old_pubkey_evil = 4; +} + +message StringList { + repeated string value = 1; +} \ No newline at end of file diff --git a/src/AElf.Client.Protobuf/Protobuf/vote_contract.proto b/src/AElf.Client.Protobuf/Protobuf/vote_contract.proto new file mode 100644 index 0000000..2c7e0e6 --- /dev/null +++ b/src/AElf.Client.Protobuf/Protobuf/vote_contract.proto @@ -0,0 +1,311 @@ +/** + * Vote contract. + */ +syntax = "proto3"; + +package Vote; + +import "aelf/core.proto"; +import "google/protobuf/timestamp.proto"; +import "aelf/options.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; + +option csharp_namespace = "AElf.Contracts.Vote"; + +service VoteContract { + option (aelf.csharp_state) = "AElf.Contracts.Vote.VoteContractState"; + + // Create a voting activity. + rpc Register (VotingRegisterInput) returns (google.protobuf.Empty) { + } + + // After successfully creating a voting activity, others are able to vote. + rpc Vote (VoteInput) returns (google.protobuf.Empty) { + } + + // A voter can withdraw the token after the lock time. + rpc Withdraw (WithdrawInput) returns (google.protobuf.Empty) { + } + + // Save the result of the specified number of votes and generates a new round votes. + rpc TakeSnapshot (TakeSnapshotInput) returns (google.protobuf.Empty) { + } + + // Add an option to a voting activity. + rpc AddOption (AddOptionInput) returns (google.protobuf.Empty) { + } + + // Remove an option from a voting activity. + rpc RemoveOption (RemoveOptionInput) returns (google.protobuf.Empty) { + } + + // Add multiple options to a voting activity. + rpc AddOptions (AddOptionsInput) returns (google.protobuf.Empty) { + } + + // Remove multiple options from a voting activity. + rpc RemoveOptions (RemoveOptionsInput) returns (google.protobuf.Empty) { + } + + // Get a voting activity information. + rpc GetVotingItem (GetVotingItemInput) returns (VotingItem) { + option (aelf.is_view) = true; + } + + // Get a voting result according to the provided voting activity id and snapshot number. + rpc GetVotingResult (GetVotingResultInput) returns (VotingResult) { + option (aelf.is_view) = true; + } + + // Gets the latest result according to the voting activity id. + rpc GetLatestVotingResult (aelf.Hash) returns (VotingResult) { + option (aelf.is_view) = true; + } + + // Get the voting record according to vote id. + rpc GetVotingRecord (aelf.Hash) returns (VotingRecord) { + option (aelf.is_view) = true; + } + + // Get the voting record according to vote ids. + rpc GetVotingRecords (GetVotingRecordsInput) returns (VotingRecords) { + option (aelf.is_view) = true; + } + + // Get all voted information according to voter address. + rpc GetVotedItems (aelf.Address) returns (VotedItems) { + option (aelf.is_view) = true; + } + + // Get the vote ids according to voting activity id. + rpc GetVotingIds (GetVotingIdsInput) returns (VotedIds) { + option (aelf.is_view) = true; + } +} + +message VotingRegisterInput { + // The start time of the voting. + google.protobuf.Timestamp start_timestamp = 1; + // The end time of the voting. + google.protobuf.Timestamp end_timestamp = 2; + // The token symbol which will be accepted. + string accepted_currency = 3; + // Whether the vote will lock token. + bool is_lock_token = 4; + // The total number of snapshots of the vote. + int64 total_snapshot_number = 5; + // The list of options. + repeated string options = 6; +} + +message VotingItem { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The token symbol which will be accepted. + string accepted_currency = 2; + // Whether the vote will lock token. + bool is_lock_token = 3; + // The current snapshot number. + int64 current_snapshot_number = 4; + // The total snapshot number. + int64 total_snapshot_number = 5; + // The list of options. + repeated string options = 6; + // The register time of the voting activity. + google.protobuf.Timestamp register_timestamp = 7; + // The start time of the voting. + google.protobuf.Timestamp start_timestamp = 8; + // The end time of the voting. + google.protobuf.Timestamp end_timestamp = 9; + // The start time of current round of the voting. + google.protobuf.Timestamp current_snapshot_start_timestamp = 10; + // The sponsor address of the voting activity. + aelf.Address sponsor = 11; +} + +message VoteInput { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The address of voter. + aelf.Address voter = 2; + // The amount of vote. + int64 amount = 3; + // The option to vote. + string option = 4; + // The vote id. + aelf.Hash vote_id = 5; + // Whether vote others. + bool is_change_target = 6; +} + +message WithdrawInput { + // The vote id. + aelf.Hash vote_id = 1; +} + +message GetVotingResultInput { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The snapshot number. + int64 snapshot_number = 2; +} + +message VotingResult { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The voting result, option -> amount of votes, + map results = 2; + // The snapshot number. + int64 snapshot_number = 3; + // The total number of voters. + int64 voters_count = 4; + // The start time of this snapshot. + google.protobuf.Timestamp snapshot_start_timestamp = 5; + // The end time of this snapshot. + google.protobuf.Timestamp snapshot_end_timestamp = 6; + // Total votes received during the process of this snapshot. + int64 votes_amount = 7; +} + +message TakeSnapshotInput { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The snapshot number to take. + int64 snapshot_number = 2; +} + +message VotingRecord { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The address of voter. + aelf.Address voter = 2; + // The snapshot number. + int64 snapshot_number = 3; + // The amount of vote. + int64 amount = 4; + // The time of withdraw. + google.protobuf.Timestamp withdraw_timestamp = 5; + // The time of vote. + google.protobuf.Timestamp vote_timestamp = 6; + // Whether the vote had been withdrawn. + bool is_withdrawn = 7; + // The option voted. + string option = 8; + // Whether vote others. + bool is_change_target = 9; +} + +message AddOptionInput { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The new option to add. + string option = 2; +} + +message RemoveOptionInput { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The option to remove. + string option = 2; +} + +message AddOptionsInput { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The new options to add. + repeated string options = 2; +} + +message RemoveOptionsInput { + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The options to remove. + repeated string options = 2; +} + +message VotedItems { + // The voted ids. + map voted_item_vote_ids = 1; +} + +message VotedIds { + // The active vote ids. + repeated aelf.Hash active_votes = 1; + // The withdrawn vote ids. + repeated aelf.Hash withdrawn_votes = 2; +} + +message GetVotingIdsInput { + // The address of voter. + aelf.Address voter = 1; + // The voting activity id. + aelf.Hash voting_item_id = 2; +} + +message GetVotingItemInput { + // The voting activity id. + aelf.Hash voting_item_id = 1; +} + +message GetVotingRecordsInput { + // The vote ids. + repeated aelf.Hash ids = 1; +} + +message VotingRecords { + // The voting records. + repeated VotingRecord records = 1; +} + +message Voted { + option (aelf.is_event) = true; + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The address of voter. + aelf.Address voter = 2; + // The snapshot number. + int64 snapshot_number = 3; + // The amount of vote. + int64 amount = 4; + // The time of vote. + google.protobuf.Timestamp vote_timestamp = 5; + // The option voted. + string option = 6; + // The vote id. + aelf.Hash vote_id = 7; +} + +message Withdrawn { + option (aelf.is_event) = true; + // The vote id. + aelf.Hash vote_id = 1; + aelf.Hash voting_item_id = 2; + int64 amount = 3; + string option = 4; + aelf.Address voter = 5; +} + +message VotingItemRegistered { + option (aelf.is_event) = true; + // The voting activity id. + aelf.Hash voting_item_id = 1; + // The token symbol which will be accepted. + string accepted_currency = 2; + // Whether the vote will lock token. + bool is_lock_token = 3; + // The current snapshot number. + int64 current_snapshot_number = 4; + // The total number of snapshots of the vote. + int64 total_snapshot_number = 5; + // The register time of the voting activity. + google.protobuf.Timestamp register_timestamp = 6; + // The start time of the voting. + google.protobuf.Timestamp start_timestamp = 7; + // The end time of the voting. + google.protobuf.Timestamp end_timestamp = 8; + // The start time of current round of the voting. + google.protobuf.Timestamp current_snapshot_start_timestamp = 9; + // The sponsor address of the voting activity. + aelf.Address sponsor = 10; +} \ No newline at end of file diff --git a/src/AElf.Client/AElf.Client.csproj b/src/AElf.Client/AElf.Client.csproj new file mode 100644 index 0000000..9d9eca7 --- /dev/null +++ b/src/AElf.Client/AElf.Client.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.1;net6.0 + enable + AElf.Client + This is a C# client library, used to communicate with the AElf API. + AElf + true + + + + + + + + + + + + + + diff --git a/AElf.Client/Service/BlockAppService.cs b/src/AElf.Client/AElfClient.Block.cs similarity index 75% rename from AElf.Client/Service/BlockAppService.cs rename to src/AElf.Client/AElfClient.Block.cs index 2fc5fbb..9c5eefe 100644 --- a/AElf.Client/Service/BlockAppService.cs +++ b/src/AElf.Client/AElfClient.Block.cs @@ -1,17 +1,10 @@ using System.Threading.Tasks; using AElf.Client.Dto; +using AElf.Client.Services; -namespace AElf.Client.Service +namespace AElf.Client { - public interface IBlockAppService - { - Task GetBlockHeightAsync(); - - Task GetBlockByHashAsync(string blockHash, bool includeTransactions = false); - - Task GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false); - } - + public partial class AElfClient : IBlockAppService { /// @@ -23,32 +16,32 @@ public async Task GetBlockHeightAsync() var url = GetRequestUrl(_baseUrl, "api/blockChain/blockHeight"); return await _httpService.GetResponseAsync(url); } - + /// /// Get information of a block by given block hash. Optional whether to include transaction information. /// /// /// /// Block information - public async Task GetBlockByHashAsync(string blockHash, bool includeTransactions = false) + public async Task GetBlockByHashAsync(string blockHash, bool includeTransactions = false) { AssertValidHash(blockHash); var url = GetRequestUrl(_baseUrl, $"api/blockChain/block?blockHash={blockHash}&includeTransactions={includeTransactions}"); return await _httpService.GetResponseAsync(url); } - + /// /// Get information of a block by specified height. Optional whether to include transaction information. /// /// /// /// Block information - public async Task GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false) + public async Task GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false) { var url = GetRequestUrl(_baseUrl, $"api/blockChain/blockByHeight?blockHeight={blockHeight}&includeTransactions={includeTransactions}"); return await _httpService.GetResponseAsync(url); } } -} \ No newline at end of file +} diff --git a/AElf.Client/Service/ChainAppService.cs b/src/AElf.Client/AElfClient.Chain.cs similarity index 54% rename from AElf.Client/Service/ChainAppService.cs rename to src/AElf.Client/AElfClient.Chain.cs index b5eb743..a346c06 100644 --- a/AElf.Client/Service/ChainAppService.cs +++ b/src/AElf.Client/AElfClient.Chain.cs @@ -2,21 +2,9 @@ using System.Threading.Tasks; using AElf.Client.Dto; -namespace AElf.Client.Service +namespace AElf.Client { - public interface IChainAppService - { - Task GetChainStatusAsync(); - - Task GetContractFileDescriptorSetAsync(string address); - - Task GetCurrentRoundInformationAsync(); - - Task> GetTaskQueueStatusAsync(); - - Task GetChainIdAsync(); - } - + public partial class AElfClient : IChainAppService { /// @@ -26,31 +14,33 @@ public partial class AElfClient : IChainAppService public async Task GetChainStatusAsync() { var url = GetRequestUrl(_baseUrl, "api/blockChain/chainStatus"); - return await _httpService.GetResponseAsync(url); + var chainStatus = await _httpService.GetResponseAsync(url); + if (chainStatus == null) + { + throw new AElfClientException("Failed to get chain status"); + } + + return chainStatus; } - + /// /// Get the definitions of proto-buff related to a contract. /// /// /// Definitions of proto-buff - public async Task GetContractFileDescriptorSetAsync(string address) + public async Task GetContractFileDescriptorSetAsync(string? address) { AssertValidAddress(address); var url = GetRequestUrl(_baseUrl, $"api/blockChain/contractFileDescriptorSet?address={address}"); - return await _httpService.GetResponseAsync(url); + var set = await _httpService.GetResponseAsync(url); + if (set == null) + { + throw new AElfClientException("Failed to get chain status"); + } + + return set; } - - /// - /// Get the latest round of consensus information from data on the last blockHeader of best-chain. - /// - /// The latest round of consensus information - public async Task GetCurrentRoundInformationAsync() - { - var url = GetRequestUrl(_baseUrl, "api/blockChain/currentRoundInformation"); - return await _httpService.GetResponseAsync(url); - } - + /// /// Gets the status information of the task queue. /// @@ -58,21 +48,26 @@ public async Task GetCurrentRoundInformationAsync() public async Task> GetTaskQueueStatusAsync() { var url = GetRequestUrl(_baseUrl, "api/blockChain/taskQueueStatus"); - return await _httpService.GetResponseAsync>(url); + + var taskQueueInfoList = await _httpService.GetResponseAsync>(url); + if (taskQueueInfoList == null) + { + throw new AElfClientException("Failed to get chain status"); + } + + return taskQueueInfoList; } - + /// /// Get id of the chain. /// /// ChainId public async Task GetChainIdAsync() { - var url = GetRequestUrl(_baseUrl, "api/blockChain/chainStatus"); - var statusDto = await _httpService.GetResponseAsync(url); - var base58ChainId = statusDto.ChainId; + var chainStatus = await GetChainStatusAsync(); + var base58ChainId = chainStatus.ChainId; var chainId = ChainHelper.ConvertBase58ToChainId(base58ChainId); - return chainId; } } -} \ No newline at end of file +} diff --git a/src/AElf.Client/AElfClient.Client.cs b/src/AElf.Client/AElfClient.Client.cs new file mode 100644 index 0000000..fa42262 --- /dev/null +++ b/src/AElf.Client/AElfClient.Client.cs @@ -0,0 +1,274 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AElf.Client.Dto; +using AElf.Client.Extensions; +using AElf.Client.Model; +using AElf.Client.Services; +using AElf.Cryptography; +using AElf.Cryptography.ECDSA; +using AElf.Types; +using Google.Protobuf; +using Google.Protobuf.WellKnownTypes; + +namespace AElf.Client +{ + + public partial class AElfClient : IClientService + { + /// + /// Verify whether this sdk successfully connects the chain. + /// + /// IsConnected or not + public async Task IsConnectedAsync() + { + try + { + var chainStatus = await GetChainStatusAsync(); + return chainStatus != null; + } + catch (Exception) + { + return false; + } + } + + /// + /// Get the address of genesis contract. + /// + /// Address + public async Task GetGenesisContractAddressAsync() + { + var statusDto = await GetChainStatusAsync(); + var genesisAddress = statusDto?.GenesisContractAddress; + return genesisAddress; + } + + /// + /// Get address of a contract by given contractNameHash. + /// + /// + /// Address + public async Task
GetContractAddressByNameAsync(Hash contractNameHash) + { + var from = GetAddressFromPrivateKey(AElfClientConstants.DefaultPrivateKey); + var to = await GetGenesisContractAddressAsync(); + var transaction = await GenerateTransactionAsync(from, to, "GetContractAddressByName", contractNameHash); + var txWithSig = SignTransaction(AElfClientConstants.DefaultPrivateKey, transaction); + + var response = await ExecuteTransactionAsync(new ExecuteTransactionDto + { + RawTransaction = txWithSig.ToByteArray().ToHex() + }); + var byteArray = ByteArrayHelper.HexStringToByteArray(response); + var address = Address.Parser.ParseFrom(byteArray); + + return address; + } + + /// + /// Build a transaction from the input parameters. + /// + /// + /// + /// + /// + /// Transaction unsigned + public async Task GenerateTransactionAsync(string? from, string? to, + string methodName, IMessage input) + { + try + { + AssertValidAddress(to); + var chainStatus = await GetChainStatusAsync(); + var transaction = new Transaction + { + From = from.ToAddress(), + To = Address.FromBase58(to), + MethodName = methodName, + Params = input.ToByteString(), + RefBlockNumber = chainStatus.BestChainHeight, + RefBlockPrefix = ByteString.CopyFrom(Hash.LoadFromHex(chainStatus.BestChainHash).Value + .Take(4).ToArray()) + }; + + return transaction; + } + catch (Exception ex) + { + throw new AElfClientException($"Failed to generate transaction: {ex.Message}"); + } + } + + /// + /// Convert the Address to the displayed string:symbol_base58-string_base58-string-chain-id + /// + /// + /// + public async Task GetFormattedAddressAsync(Address address) + { + var tokenContractAddress = await GetContractAddressByNameAsync(HashHelper.ComputeFrom("AElf.ContractNames.Token")); + var fromAddress = GetAddressFromPrivateKey(AElfClientConstants.DefaultPrivateKey); + var toAddress = tokenContractAddress.ToBase58(); + var methodName = "GetPrimaryTokenSymbol"; + var param = new Empty(); + + var transaction = await GenerateTransactionAsync(fromAddress, toAddress, methodName, param); + var txWithSign = SignTransaction(AElfClientConstants.DefaultPrivateKey, transaction); + + var result = await ExecuteTransactionAsync(new ExecuteTransactionDto + { + RawTransaction = txWithSign.ToByteArray().ToHex() + }); + + var symbol = StringValue.Parser.ParseFrom(ByteArrayHelper.HexStringToByteArray(result)); + var chainIdString = (await GetChainStatusAsync())?.ChainId; + + return $"{symbol.Value}_{address.ToBase58()}_{chainIdString}"; + } + + /// + /// Sign a transaction using private key. + /// + /// + /// + /// Transaction signed + public Transaction SignTransaction(string? privateKeyHex, Transaction transaction) + { + var transactionData = transaction.GetHash().ToByteArray(); + + privateKeyHex ??= AElfClientConstants.DefaultPrivateKey; + + // Sign the hash + var privateKey = ByteArrayHelper.HexStringToByteArray(privateKeyHex); + var signature = CryptoHelper.SignWithPrivateKey(privateKey, transactionData); + transaction.Signature = ByteString.CopyFrom(signature); + + return transaction; + } + + /// + /// Sign a transaction using private key. + /// + /// + /// + /// Transaction signed + public Transaction SignTransaction(byte[]? privateKey, Transaction transaction) + { + var transactionData = transaction.GetHash().ToByteArray(); + + privateKey ??= ByteArrayHelper.HexStringToByteArray(AElfClientConstants.DefaultPrivateKey); + + // Sign the hash + var signature = CryptoHelper.SignWithPrivateKey(privateKey, transactionData); + transaction.Signature = ByteString.CopyFrom(signature); + + return transaction; + } + + /// + /// Get the account address through the public key. + /// + /// + /// Account + public string GetAddressFromPubKey(string pubKey) + { + var publicKey = ByteArrayHelper.HexStringToByteArray(pubKey); + var address = Address.FromPublicKey(publicKey); + return address.ToBase58(); + } + + /// + /// Get the account address through the private key. + /// + /// + /// + public string? GetAddressFromPrivateKey(string? privateKeyHex) + { + var address = Address.FromPublicKey(GetAElfKeyPair(privateKeyHex).PublicKey); + return address.ToBase58(); + } + + public Address GetBase58String(string base58String) + { + return Address.FromBase58(base58String); + } + + public KeyPairInfo GenerateKeyPairInfo() + { + var keyPair = CryptoHelper.GenerateKeyPair(); + var privateKey = keyPair.PrivateKey.ToHex(); + var publicKey = keyPair.PublicKey.ToHex(); + var address = GetAddressFromPrivateKey(privateKey); + + return new KeyPairInfo + { + PrivateKey = privateKey, + PublicKey = publicKey, + Address = address + }; + } + + #region private methods + + private ECKeyPair GetAElfKeyPair(string? privateKeyHex) + { + var privateKey = ByteArrayHelper.HexStringToByteArray(privateKeyHex); + var keyPair = CryptoHelper.FromPrivateKey(privateKey); + + return keyPair; + } + + private string GetRequestUrl(string baseUrl, string relativeUrl) + { + return new Uri(new Uri(baseUrl + (baseUrl.EndsWith("/") ? "" : "/")), relativeUrl).ToString(); + } + + private void AssertValidAddress(params string?[] addresses) + { + try + { + foreach (var address in addresses) + { + Address.FromBase58(address); + } + } + catch (Exception) + { + throw new AElfClientException(Error.Message[Error.InvalidAddress]); + } + } + + private void AssertValidHash(params string[] hashes) + { + try + { + foreach (var hash in hashes) + { + Hash.LoadFromHex(hash); + } + } + catch (Exception) + { + throw new AElfClientException(Error.Message[Error.InvalidBlockHash]); + } + } + + private void AssertValidTransactionId(params string[] transactionIds) + { + try + { + foreach (var transactionId in transactionIds) + { + Hash.LoadFromHex(transactionId); + } + } + catch (Exception) + { + throw new AElfClientException(Error.Message[Error.InvalidTransactionId]); + } + } + + #endregion + } +} diff --git a/src/AElf.Client/AElfClient.Net.cs b/src/AElf.Client/AElfClient.Net.cs new file mode 100644 index 0000000..723e019 --- /dev/null +++ b/src/AElf.Client/AElfClient.Net.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using AElf.Client.Dto; +using AElf.Client.Helper; +using AElf.Client.Services; + +namespace AElf.Client +{ + + public partial class AElfClient : INetAppService + { + /// + /// Attempt to add a node to the connected network nodes.Input parameter contains the ipAddress of the node. + /// + /// + /// + /// + /// Add successfully or not + public async Task AddPeerAsync(string ipAddress, string userName, string password) + { + if (!EndpointHelper.TryParse(ipAddress, out var endpoint)) + { + return false; + } + + var url = GetRequestUrl(_baseUrl, "api/net/peer"); + var parameters = new Dictionary + { + {"address", endpoint?.ToString() ?? AElfClientConstants.LocalEndpoint} + }; + + return await _httpService.PostResponseAsync(url, parameters, + authenticationHeaderValue: GetAuthenticationHeaderValue()); + } + + /// + /// Attempt to remove a node from the connected network nodes by given the ipAddress. + /// + /// + /// + /// + /// Delete successfully or not + public async Task RemovePeerAsync(string ipAddress, string userName, string password) + { + if (!EndpointHelper.TryParse(ipAddress, out var endpoint)) + { + return false; + } + + var url = GetRequestUrl(_baseUrl, $"api/net/peer?address={endpoint}"); + return await _httpService.DeleteResponseAsObjectAsync(url, + authenticationHeaderValue: GetAuthenticationHeaderValue()); + } + + /// + /// Gets information about the peer nodes of the current node.Optional whether to include metrics. + /// + /// + /// Information about the peer nodes + public async Task?> GetPeersAsync(bool withMetrics) + { + var url = GetRequestUrl(_baseUrl, $"api/net/peers?withMetrics={withMetrics}"); + return await _httpService.GetResponseAsync>(url); + } + + /// + /// Get the node's network information. + /// + /// Network information + public async Task GetNetworkInfoAsync() + { + var url = GetRequestUrl(_baseUrl, "api/net/networkInfo"); + return await _httpService.GetResponseAsync(url); + } + + private AuthenticationHeaderValue GetAuthenticationHeaderValue() + { + var byteArray = Encoding.ASCII.GetBytes($"{_userName}:{_password}"); + return new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); + } + } +} diff --git a/src/AElf.Client/AElfClient.Transaction.cs b/src/AElf.Client/AElfClient.Transaction.cs new file mode 100644 index 0000000..d05a497 --- /dev/null +++ b/src/AElf.Client/AElfClient.Transaction.cs @@ -0,0 +1,179 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AElf.Client.Dto; +using AElf.Client.Services; + +namespace AElf.Client +{ + + public partial class AElfClient : ITransactionAppService + { + /// + /// Get information about the current transaction pool. + /// + /// TransactionPoolStatusOutput + public async Task GetTransactionPoolStatusAsync() + { + var url = GetRequestUrl(_baseUrl, "api/blockChain/transactionPoolStatus"); + return await _httpService.GetResponseAsync(url); + } + + /// + /// Call a read-only method of a contract. + /// + /// + /// + public async Task ExecuteTransactionAsync(ExecuteTransactionDto input) + { + var url = GetRequestUrl(_baseUrl, "api/blockChain/executeTransaction"); + var parameters = new Dictionary + { + {"RawTransaction", input.RawTransaction} + }; + + var result = await _httpService.PostResponseAsync(url, parameters); + + if (result == null) + { + throw new AElfClientException("Failed to execute tx."); + } + + return result; + } + + /// + /// Call a method of a contract by given serialized strings. + /// + /// + /// Serialized result + public async Task ExecuteRawTransactionAsync(ExecuteRawTransactionDto input) + { + var url = GetRequestUrl(_baseUrl, "api/blockChain/executeRawTransaction"); + var parameters = new Dictionary + { + {"RawTransaction", input.RawTransaction}, + {"Signature", input.Signature} + }; + + return await _httpService.PostResponseAsync(url, parameters); + } + + /// + /// Creates an unsigned serialized transaction. + /// + /// + /// CreateRawTransactionOutput + public async Task CreateRawTransactionAsync(CreateRawTransactionInput input) + { + var url = GetRequestUrl(_baseUrl, "api/blockChain/rawTransaction"); + var parameters = new Dictionary + { + {"From", input.From}, + {"To", input.To}, + {"RefBlockNumber", input.RefBlockNumber.ToString()}, + {"RefBlockHash", input.RefBlockHash}, + {"MethodName", input.MethodName}, + {"Params", input.Params} + }; + + return await _httpService.PostResponseAsync(url, parameters); + } + + /// + /// Broadcast a serialized transaction. + /// + /// + /// SendRawTransactionOutput + public async Task SendRawTransactionAsync(SendRawTransactionInput input) + { + var url = GetRequestUrl(_baseUrl, "api/blockChain/sendRawTransaction"); + var parameters = new Dictionary + { + {"Transaction", input.Transaction}, + {"Signature", input.Signature}, + {"ReturnTransaction", input.ReturnTransaction ? "true" : "false"} + }; + return await _httpService.PostResponseAsync(url, parameters); + } + + /// + /// Broadcast a transaction. + /// + /// + /// TransactionId + public async Task SendTransactionAsync(SendTransactionInput input) + { + var url = GetRequestUrl(_baseUrl, "api/blockChain/sendTransaction"); + var parameters = new Dictionary + { + {"RawTransaction", input.RawTransaction} + }; + return await _httpService.PostResponseAsync(url, parameters); + } + + /// + /// Broadcast volume transactions. + /// + /// + /// TransactionIds + public async Task SendTransactionsAsync(SendTransactionsInput input) + { + var url = GetRequestUrl(_baseUrl, "api/blockChain/sendTransactions"); + var parameters = new Dictionary + { + {"RawTransactions", input.RawTransactions} + }; + return await _httpService.PostResponseAsync(url, parameters); + } + + /// + /// Gets the result of transaction execution by the given transactionId. + /// + /// + /// TransactionResultDto + public async Task GetTransactionResultAsync(string transactionId) + { + AssertValidTransactionId(transactionId); + var url = GetRequestUrl(_baseUrl, $"api/blockChain/transactionResult?transactionId={transactionId}"); + return await _httpService.GetResponseAsync(url); + } + + /// + /// Get results of multiple transactions by specified blockHash and the offset. + /// + /// + /// + /// + /// TransactionResultDtos + public async Task?> GetTransactionResultsAsync(string blockHash, int offset = 0, + int limit = 10) + { + AssertValidHash(blockHash); + var url = GetRequestUrl(_baseUrl, + $"api/blockChain/transactionResults?blockHash={blockHash}&offset={offset}&limit={limit}"); + return await _httpService.GetResponseAsync>(url); + } + + /// + /// Get merkle path of a transaction. + /// + /// + /// MerklePathDto + public async Task GetMerklePathByTransactionIdAsync(string transactionId) + { + AssertValidTransactionId(transactionId); + var url = GetRequestUrl(_baseUrl, $"api/blockChain/merklePathByTransactionId?transactionId={transactionId}"); + return await _httpService.GetResponseAsync(url); + } + + public async Task CalculateTransactionFeeAsync(CalculateTransactionFeeInput input) + { + var url = GetRequestUrl(_baseUrl, "/api/blockChain/calculateTransactionFee"); + var parameters = new Dictionary + { + {"RawTransaction", input.RawTransaction} + }; + return await _httpService.PostResponseAsync(url,parameters); + } + } +} diff --git a/src/AElf.Client/AElfClient.cs b/src/AElf.Client/AElfClient.cs new file mode 100644 index 0000000..8faaff9 --- /dev/null +++ b/src/AElf.Client/AElfClient.cs @@ -0,0 +1,39 @@ +using System; +using AElf.Client.Service; + +namespace AElf.Client +{ + public partial class AElfClient : IDisposable + { + private readonly IHttpService _httpService; + private readonly string _baseUrl; + private readonly string _userName; + private readonly string _password; + + public AElfClient(string baseUrl, int timeOut = 60, string userName = null, string password = null) + { + _httpService = new HttpService(timeOut); + _baseUrl = baseUrl; + _userName = userName; + _password = password; + } + + private bool _disposed; + + /// + public void Dispose() + { + if (_disposed) return; + Dispose(true); + _disposed = true; + } + + /// + /// Disposes the resources associated with the object. + /// + /// true if called by a call to the Dispose method; otherwise false. + protected virtual void Dispose(bool disposing) + { + } + } +} \ No newline at end of file diff --git a/src/AElf.Client/AElfClientBuilder.cs b/src/AElf.Client/AElfClientBuilder.cs new file mode 100644 index 0000000..1d3d6eb --- /dev/null +++ b/src/AElf.Client/AElfClientBuilder.cs @@ -0,0 +1,67 @@ +namespace AElf.Client +{ + + public sealed class AElfClientBuilder + { + private string NodeEndpoint { get; set; } + private int Timeout { get; set; } + + private string UserName { get; set; } + private string Password { get; set; } + + public AElfClientBuilder() + { + NodeEndpoint = AElfClientConstants.LocalEndpoint; + Timeout = 60; + } + + public AElfClientBuilder UseEndpoint(string endpoint) + { + NodeEndpoint = endpoint; + return this; + } + + public AElfClientBuilder UsePublicEndpoint(EndpointType endpointType) + { + switch (endpointType) + { + case EndpointType.MainNetMainChain: + NodeEndpoint = AElfClientConstants.MainNetMainChain; + break; + case EndpointType.MainNetSidechain: + NodeEndpoint = AElfClientConstants.MainNetSidechain; + break; + case EndpointType.TestNetMainChain: + NodeEndpoint = AElfClientConstants.TestNetMainChain; + break; + case EndpointType.TestNetSidechain: + NodeEndpoint = AElfClientConstants.TestNetSidechain; + break; + case EndpointType.Local: + default: + NodeEndpoint = AElfClientConstants.LocalEndpoint; + break; + } + + return this; + } + + public AElfClientBuilder SetHttpTimeout(int timeout) + { + Timeout = timeout; + return this; + } + + public AElfClientBuilder ManagePeerInfo(string userName, string password) + { + UserName = userName; + Password = password; + return this; + } + + public AElfClient Build() + { + return new AElfClient(NodeEndpoint, Timeout, UserName, Password); + } + } +} diff --git a/src/AElf.Client/AElfClientConstants.cs b/src/AElf.Client/AElfClientConstants.cs new file mode 100644 index 0000000..d611cd3 --- /dev/null +++ b/src/AElf.Client/AElfClientConstants.cs @@ -0,0 +1,15 @@ +namespace AElf.Client +{ + + public class AElfClientConstants + { + public const string DefaultPrivateKey = "09da44778f8db2e602fb484334f37df19e221c84c4582ce5b7770ccfbc3ddbef"; + public const string LocalEndpoint = "http://127.0.0.1:1235"; + public const string MainNetMainChain = "https://aelf-public-node.aelf.io"; + public const string MainNetSidechain = "https://tdvv-public-node.aelf.io"; + public const string TestNetMainChain = "https://aelf-test-node.aelf.io"; + public const string TestNetSidechain = "https://tdvv-test-node.aelf.io"; + public const int MainChainId = 9992731; + public const int SidechainId = 9992731; + } +} diff --git a/AElf.Client/Dto/BlockBodyDto.cs b/src/AElf.Client/Dto/BlockBodyDto.cs similarity index 91% rename from AElf.Client/Dto/BlockBodyDto.cs rename to src/AElf.Client/Dto/BlockBodyDto.cs index 848ad98..059d50e 100644 --- a/AElf.Client/Dto/BlockBodyDto.cs +++ b/src/AElf.Client/Dto/BlockBodyDto.cs @@ -2,10 +2,11 @@ namespace AElf.Client.Dto { + public class BlockBodyDto { public int TransactionsCount { get; set; } - + public List Transactions { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/BlockDto.cs b/src/AElf.Client/Dto/BlockDto.cs similarity index 86% rename from AElf.Client/Dto/BlockDto.cs rename to src/AElf.Client/Dto/BlockDto.cs index db23a43..8ae6f6b 100644 --- a/AElf.Client/Dto/BlockDto.cs +++ b/src/AElf.Client/Dto/BlockDto.cs @@ -1,11 +1,12 @@ namespace AElf.Client.Dto { + public class BlockDto { public string BlockHash { get; set; } - + public BlockHeaderDto Header { get; set; } - + public BlockBodyDto Body { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/BlockHeaderDto.cs b/src/AElf.Client/Dto/BlockHeaderDto.cs similarity index 92% rename from AElf.Client/Dto/BlockHeaderDto.cs rename to src/AElf.Client/Dto/BlockHeaderDto.cs index d07862a..7651228 100644 --- a/AElf.Client/Dto/BlockHeaderDto.cs +++ b/src/AElf.Client/Dto/BlockHeaderDto.cs @@ -2,26 +2,27 @@ namespace AElf.Client.Dto { + public class BlockHeaderDto { public string PreviousBlockHash { get; set; } - + public string MerkleTreeRootOfTransactions { get; set; } - + public string MerkleTreeRootOfWorldState { get; set; } - + public string MerkleTreeRootOfTransactionState { get; set; } - + public string Extra { get; set; } - + public long Height { get; set; } - + public DateTime Time { get; set; } - + public string ChainId { get; set; } - + public string Bloom { get; set; } - + public string SignerPubkey { get; set; } } -} \ No newline at end of file +} diff --git a/src/AElf.Client/Dto/CalculateTransactionFeeInput.cs b/src/AElf.Client/Dto/CalculateTransactionFeeInput.cs new file mode 100644 index 0000000..03f26a9 --- /dev/null +++ b/src/AElf.Client/Dto/CalculateTransactionFeeInput.cs @@ -0,0 +1,8 @@ +namespace AElf.Client.Dto +{ + + public class CalculateTransactionFeeInput + { + public string RawTransaction { get; set; } + } +} diff --git a/src/AElf.Client/Dto/CalculateTransactionFeeOutput.cs b/src/AElf.Client/Dto/CalculateTransactionFeeOutput.cs new file mode 100644 index 0000000..3f220b5 --- /dev/null +++ b/src/AElf.Client/Dto/CalculateTransactionFeeOutput.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace AElf.Client.Dto +{ + + public class CalculateTransactionFeeOutput + { + + public bool Success { get; set; } + + public Dictionary TransactionFee { get; set; } + + public Dictionary ResourceFee { get; set; } + } +} diff --git a/AElf.Client/Dto/ChainStatusDto.cs b/src/AElf.Client/Dto/ChainStatusDto.cs similarity index 84% rename from AElf.Client/Dto/ChainStatusDto.cs rename to src/AElf.Client/Dto/ChainStatusDto.cs index 76436b4..a52a8f1 100644 --- a/AElf.Client/Dto/ChainStatusDto.cs +++ b/src/AElf.Client/Dto/ChainStatusDto.cs @@ -2,28 +2,29 @@ namespace AElf.Client.Dto { + public class ChainStatusDto { public string ChainId { get; set; } - + public Dictionary Branches { get; set; } - + public Dictionary NotLinkedBlocks { get; set; } - + public long LongestChainHeight { get; set; } - + public string LongestChainHash { get; set; } - + public string GenesisBlockHash { get; set; } - + public string GenesisContractAddress { get; set; } - + public string LastIrreversibleBlockHash { get; set; } - + public long LastIrreversibleBlockHeight { get; set; } - + public string BestChainHash { get; set; } - + public long BestChainHeight { get; set; } } -} \ No newline at end of file +} diff --git a/src/AElf.Client/Dto/CreateRawTransactionInput.cs b/src/AElf.Client/Dto/CreateRawTransactionInput.cs new file mode 100644 index 0000000..02d2519 --- /dev/null +++ b/src/AElf.Client/Dto/CreateRawTransactionInput.cs @@ -0,0 +1,35 @@ +namespace AElf.Client.Dto +{ + public class CreateRawTransactionInput + { + /// + /// from address + /// + public string From { get; set; } + + /// + /// to address + /// + public string To { get; set; } + + /// + /// refer block height + /// + public long RefBlockNumber { get; set; } + + /// + /// refer block hash + /// + public string RefBlockHash { get; set; } + + /// + /// contract method name + /// + public string MethodName { get; set; } + + /// + /// contract method parameters + /// + public string Params { get; set; } + } +} \ No newline at end of file diff --git a/AElf.Client/Dto/CreateRawTransactionOutput.cs b/src/AElf.Client/Dto/CreateRawTransactionOutput.cs similarity index 95% rename from AElf.Client/Dto/CreateRawTransactionOutput.cs rename to src/AElf.Client/Dto/CreateRawTransactionOutput.cs index 3925ed2..babe46c 100644 --- a/AElf.Client/Dto/CreateRawTransactionOutput.cs +++ b/src/AElf.Client/Dto/CreateRawTransactionOutput.cs @@ -1,7 +1,8 @@ namespace AElf.Client.Dto { + public class CreateRawTransactionOutput { public string RawTransaction { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/ExecuteRawTransactionDto.cs b/src/AElf.Client/Dto/ExecuteRawTransactionDto.cs similarity index 96% rename from AElf.Client/Dto/ExecuteRawTransactionDto.cs rename to src/AElf.Client/Dto/ExecuteRawTransactionDto.cs index 85fa740..e229467 100644 --- a/AElf.Client/Dto/ExecuteRawTransactionDto.cs +++ b/src/AElf.Client/Dto/ExecuteRawTransactionDto.cs @@ -1,15 +1,16 @@ namespace AElf.Client.Dto { + public class ExecuteRawTransactionDto { /// /// raw transaction /// public string RawTransaction { get; set; } - + /// /// signature /// public string Signature { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/ExecuteTransactionDto.cs b/src/AElf.Client/Dto/ExecuteTransactionDto.cs similarity index 96% rename from AElf.Client/Dto/ExecuteTransactionDto.cs rename to src/AElf.Client/Dto/ExecuteTransactionDto.cs index 255fa94..d850791 100644 --- a/AElf.Client/Dto/ExecuteTransactionDto.cs +++ b/src/AElf.Client/Dto/ExecuteTransactionDto.cs @@ -1,5 +1,6 @@ namespace AElf.Client.Dto { + public class ExecuteTransactionDto { /// @@ -7,4 +8,4 @@ public class ExecuteTransactionDto /// public string RawTransaction { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/LogEventDto.cs b/src/AElf.Client/Dto/LogEventDto.cs similarity index 84% rename from AElf.Client/Dto/LogEventDto.cs rename to src/AElf.Client/Dto/LogEventDto.cs index a856231..6a7639e 100644 --- a/AElf.Client/Dto/LogEventDto.cs +++ b/src/AElf.Client/Dto/LogEventDto.cs @@ -1,13 +1,14 @@ namespace AElf.Client.Dto { + public class LogEventDto { public string Address { get; set; } - + public string Name { get; set; } - + public string[] Indexed { get; set; } - + public string NonIndexed { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/MerklePathDto.cs b/src/AElf.Client/Dto/MerklePathDto.cs similarity index 96% rename from AElf.Client/Dto/MerklePathDto.cs rename to src/AElf.Client/Dto/MerklePathDto.cs index 6880ea5..e20e50d 100644 --- a/AElf.Client/Dto/MerklePathDto.cs +++ b/src/AElf.Client/Dto/MerklePathDto.cs @@ -2,14 +2,15 @@ namespace AElf.Client.Dto { + public class MerklePathDto { public List MerklePathNodes; } - + public class MerklePathNodeDto { public string Hash { get; set; } public bool IsLeftChildNode { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/NetworkInfoOutput.cs b/src/AElf.Client/Dto/NetworkInfoOutput.cs similarity index 93% rename from AElf.Client/Dto/NetworkInfoOutput.cs rename to src/AElf.Client/Dto/NetworkInfoOutput.cs index 0bf5f6f..aa24de1 100644 --- a/AElf.Client/Dto/NetworkInfoOutput.cs +++ b/src/AElf.Client/Dto/NetworkInfoOutput.cs @@ -1,20 +1,21 @@ namespace AElf.Client.Dto { + public class NetworkInfoOutput { /// /// node version /// public string Version { get; set; } - + /// /// network protocol version /// public int ProtocolVersion { get; set; } - + /// /// total number of open connections between this node and other nodes /// public int Connections { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/PeerDto.cs b/src/AElf.Client/Dto/PeerDto.cs similarity index 93% rename from AElf.Client/Dto/PeerDto.cs rename to src/AElf.Client/Dto/PeerDto.cs index 297ba38..39fd297 100644 --- a/AElf.Client/Dto/PeerDto.cs +++ b/src/AElf.Client/Dto/PeerDto.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using Google.Protobuf.WellKnownTypes; namespace AElf.Client.Dto { + public class PeerDto { public string IpAddress { get; set; } @@ -14,8 +14,9 @@ public class PeerDto public int BufferedBlocksCount { get; set; } public int BufferedAnnouncementsCount { get; set; } public List RequestMetrics { get; set; } + public string NodeVersion { get; set; } } - + public class RequestMetric { public long RoundTripTime { get; set; } @@ -23,4 +24,4 @@ public class RequestMetric public string Info { get; set; } public string RequestTime { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/SendRawTransactionInput.cs b/src/AElf.Client/Dto/SendRawTransactionInput.cs similarity index 93% rename from AElf.Client/Dto/SendRawTransactionInput.cs rename to src/AElf.Client/Dto/SendRawTransactionInput.cs index a3896a9..382ae3e 100644 --- a/AElf.Client/Dto/SendRawTransactionInput.cs +++ b/src/AElf.Client/Dto/SendRawTransactionInput.cs @@ -1,20 +1,21 @@ namespace AElf.Client.Dto { + public class SendRawTransactionInput { /// /// raw transaction /// public string Transaction { get; set; } - + /// /// signature /// public string Signature { get; set; } - + /// /// return transaction detail or not /// public bool ReturnTransaction { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/SendRawTransactionOutput.cs b/src/AElf.Client/Dto/SendRawTransactionOutput.cs similarity index 94% rename from AElf.Client/Dto/SendRawTransactionOutput.cs rename to src/AElf.Client/Dto/SendRawTransactionOutput.cs index 77600d3..0b9487d 100644 --- a/AElf.Client/Dto/SendRawTransactionOutput.cs +++ b/src/AElf.Client/Dto/SendRawTransactionOutput.cs @@ -1,9 +1,10 @@ namespace AElf.Client.Dto { + public class SendRawTransactionOutput { public string TransactionId { get; set; } - + public TransactionDto Transaction { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/SendTransactionInput.cs b/src/AElf.Client/Dto/SendTransactionInput.cs similarity index 96% rename from AElf.Client/Dto/SendTransactionInput.cs rename to src/AElf.Client/Dto/SendTransactionInput.cs index 75be53d..f33625c 100644 --- a/AElf.Client/Dto/SendTransactionInput.cs +++ b/src/AElf.Client/Dto/SendTransactionInput.cs @@ -1,5 +1,6 @@ namespace AElf.Client.Dto { + public class SendTransactionInput { /// @@ -7,4 +8,4 @@ public class SendTransactionInput /// public string RawTransaction { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/SendTransactionOutput.cs b/src/AElf.Client/Dto/SendTransactionOutput.cs similarity index 94% rename from AElf.Client/Dto/SendTransactionOutput.cs rename to src/AElf.Client/Dto/SendTransactionOutput.cs index fefc1f2..9af68a4 100644 --- a/AElf.Client/Dto/SendTransactionOutput.cs +++ b/src/AElf.Client/Dto/SendTransactionOutput.cs @@ -1,7 +1,8 @@ namespace AElf.Client.Dto { + public class SendTransactionOutput { public string TransactionId { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/SendTransactionsInput.cs b/src/AElf.Client/Dto/SendTransactionsInput.cs similarity index 96% rename from AElf.Client/Dto/SendTransactionsInput.cs rename to src/AElf.Client/Dto/SendTransactionsInput.cs index d7808b5..33ae65d 100644 --- a/AElf.Client/Dto/SendTransactionsInput.cs +++ b/src/AElf.Client/Dto/SendTransactionsInput.cs @@ -1,5 +1,6 @@ namespace AElf.Client.Dto { + public class SendTransactionsInput { /// @@ -7,4 +8,4 @@ public class SendTransactionsInput /// public string RawTransactions { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/TaskQueueInfoDto.cs b/src/AElf.Client/Dto/TaskQueueInfoDto.cs similarity index 92% rename from AElf.Client/Dto/TaskQueueInfoDto.cs rename to src/AElf.Client/Dto/TaskQueueInfoDto.cs index 30cb32c..005cf03 100644 --- a/AElf.Client/Dto/TaskQueueInfoDto.cs +++ b/src/AElf.Client/Dto/TaskQueueInfoDto.cs @@ -1,9 +1,10 @@ namespace AElf.Client.Dto { + public class TaskQueueInfoDto { public string Name { get; set; } - + public int Size { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/TransactionDto.cs b/src/AElf.Client/Dto/TransactionDto.cs similarity index 82% rename from AElf.Client/Dto/TransactionDto.cs rename to src/AElf.Client/Dto/TransactionDto.cs index ccecb6e..b089297 100644 --- a/AElf.Client/Dto/TransactionDto.cs +++ b/src/AElf.Client/Dto/TransactionDto.cs @@ -1,19 +1,20 @@ namespace AElf.Client.Dto { + public class TransactionDto { public string From { get; set; } - + public string To { get; set; } - + public long RefBlockNumber { get; set; } - + public string RefBlockPrefix { get; set; } - + public string MethodName { get; set; } - + public string Params { get; set; } - + public string Signature { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/TransactionPoolStatusOutput.cs b/src/AElf.Client/Dto/TransactionPoolStatusOutput.cs similarity index 96% rename from AElf.Client/Dto/TransactionPoolStatusOutput.cs rename to src/AElf.Client/Dto/TransactionPoolStatusOutput.cs index 19434a1..e72f545 100644 --- a/AElf.Client/Dto/TransactionPoolStatusOutput.cs +++ b/src/AElf.Client/Dto/TransactionPoolStatusOutput.cs @@ -1,8 +1,9 @@ namespace AElf.Client.Dto { + public class TransactionPoolStatusOutput { public int Queued { get; set; } public int Validated { get; set; } } -} \ No newline at end of file +} diff --git a/AElf.Client/Dto/TransactionResultDto.cs b/src/AElf.Client/Dto/TransactionResultDto.cs similarity index 71% rename from AElf.Client/Dto/TransactionResultDto.cs rename to src/AElf.Client/Dto/TransactionResultDto.cs index 0321ea9..98caf9c 100644 --- a/AElf.Client/Dto/TransactionResultDto.cs +++ b/src/AElf.Client/Dto/TransactionResultDto.cs @@ -1,27 +1,24 @@ namespace AElf.Client.Dto { + public class TransactionResultDto { public string TransactionId { get; set; } - + public string Status { get; set; } - + public LogEventDto[] Logs { get; set; } - + public string Bloom { get; set; } - + public long BlockNumber { get; set; } - + public string BlockHash { get; set; } - + public TransactionDto Transaction { get; set; } - + public string ReturnValue { get; set; } - - public string ReadableReturnValue { get; set; } - + public string Error { get; set; } - - public TransactionFeeDto TransactionFee { get; set; } } -} \ No newline at end of file +} diff --git a/src/AElf.Client/EndpointType.cs b/src/AElf.Client/EndpointType.cs new file mode 100644 index 0000000..feec5d6 --- /dev/null +++ b/src/AElf.Client/EndpointType.cs @@ -0,0 +1,12 @@ +namespace AElf.Client +{ + + public enum EndpointType + { + MainNetMainChain, + MainNetSidechain, + TestNetMainChain, + TestNetSidechain, + Local + } +} diff --git a/AElf.Client/Exception/AElfClientException.cs b/src/AElf.Client/Exception/AElfClientException.cs similarity index 58% rename from AElf.Client/Exception/AElfClientException.cs rename to src/AElf.Client/Exception/AElfClientException.cs index 6262a0f..b588757 100644 --- a/AElf.Client/Exception/AElfClientException.cs +++ b/src/AElf.Client/Exception/AElfClientException.cs @@ -1,10 +1,13 @@ +using System; + namespace AElf.Client { - public class AElfClientException : System.Exception + + public class AElfClientException : Exception { public AElfClientException(string message) : base(message) { - + } } -} \ No newline at end of file +} diff --git a/AElf.Client/Exception/Error.cs b/src/AElf.Client/Exception/Error.cs similarity index 99% rename from AElf.Client/Exception/Error.cs rename to src/AElf.Client/Exception/Error.cs index fac133a..2a5af03 100644 --- a/AElf.Client/Exception/Error.cs +++ b/src/AElf.Client/Exception/Error.cs @@ -2,6 +2,7 @@ namespace AElf.Client { + public class Error { public const int NotFound = 20001; @@ -17,7 +18,7 @@ public class Error public const int NoMatchMethodInContractAddress = 20011; public const int InvalidParams = 20012; public const int InvalidSignature = 20013; - + public static readonly Dictionary Message = new Dictionary { {NotFound, "Not found"}, @@ -35,4 +36,4 @@ public class Error {InvalidSignature, "Invalid signature"} }; } -} \ No newline at end of file +} diff --git a/src/AElf.Client/Extensions/StringExtensions.cs b/src/AElf.Client/Extensions/StringExtensions.cs new file mode 100644 index 0000000..efbd584 --- /dev/null +++ b/src/AElf.Client/Extensions/StringExtensions.cs @@ -0,0 +1,18 @@ +using AElf.Types; + +namespace AElf.Client.Extensions +{ + + public static class StringExtensions + { + public static Address ToAddress(this string? address) + { + if (address == null) + { + return Address.FromPublicKey(ByteArrayHelper.HexStringToByteArray(AElfClientConstants.DefaultPrivateKey)); + } + + return Address.FromBase58(address); + } + } +} diff --git a/src/AElf.Client/Extensions/TransactionResultDtoExtension.cs b/src/AElf.Client/Extensions/TransactionResultDtoExtension.cs new file mode 100644 index 0000000..54a830c --- /dev/null +++ b/src/AElf.Client/Extensions/TransactionResultDtoExtension.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Linq; +using AElf.Client.Dto; +using AElf.Contracts.MultiToken; +using Google.Protobuf; + +namespace AElf.Client.Extensions +{ + + public static class TransactionResultDtoExtension + { + public static Dictionary GetTransactionFees(this TransactionResultDto transactionResultDto) + { + var result = new Dictionary(); + + var transactionFeeLogs = + transactionResultDto.Logs?.Where(l => l.Name == nameof(TransactionFeeCharged)).ToList(); + if (transactionFeeLogs != null) + { + foreach (var transactionFee in transactionFeeLogs.Select(transactionFeeLog => + TransactionFeeCharged.Parser.ParseFrom(ByteString.FromBase64(transactionFeeLog.NonIndexed)))) + { + result.Add(transactionFee.Symbol, transactionFee.Amount); + } + } + + var resourceTokenLogs = + transactionResultDto.Logs?.Where(l => l.Name == nameof(ResourceTokenCharged)).ToList(); + if (resourceTokenLogs != null) + { + foreach (var resourceToken in resourceTokenLogs.Select(transactionFeeLog => + ResourceTokenCharged.Parser.ParseFrom(ByteString.FromBase64(transactionFeeLog.NonIndexed)))) + { + result.Add(resourceToken.Symbol, resourceToken.Amount); + } + } + + return result; + } + } +} diff --git a/AElf.Client/Helper/EndpointHelper.cs b/src/AElf.Client/Helper/EndpointHelper.cs similarity index 69% rename from AElf.Client/Helper/EndpointHelper.cs rename to src/AElf.Client/Helper/EndpointHelper.cs index 8c6147d..da410e4 100644 --- a/AElf.Client/Helper/EndpointHelper.cs +++ b/src/AElf.Client/Helper/EndpointHelper.cs @@ -6,7 +6,7 @@ namespace AElf.Client.Helper { public static class EndpointHelper { - public static bool TryParse(string endpointString, out DnsEndPoint endpoint, + public static bool TryParse(string endpointString, out DnsEndPoint? endpoint, int defaultPort = 6800) { endpoint = null; @@ -17,11 +17,11 @@ public static bool TryParse(string endpointString, out DnsEndPoint endpoint, if (defaultPort != -1 && (defaultPort < IPEndPoint.MinPort || defaultPort > IPEndPoint.MaxPort)) return false; - string[] values = endpointString.Split(new[] {':'}); + var values = endpointString.Split(new[] {':'}); string host; - int port = -1; + var port = -1; - if (values.Length <= 2) + if(values.Length <= 2) { // ipv4 or hostname host = values[0]; @@ -40,27 +40,21 @@ public static bool TryParse(string endpointString, out DnsEndPoint endpoint, port = parsedPort; } } - else if (values.Length > 2) + //ipv6 + //could be [a:b:c]:d + else if(values.Length > 2 && (values[0].StartsWith("[") && values[^2].EndsWith("]"))) { - //ipv6 - //could be [a:b:c]:d - if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]")) - { - host = string.Join(":", values.Take(values.Length - 1).ToArray()); - var parsedPort = GetPort(values[values.Length - 1]); + host = string.Join(":", values.Take(values.Length - 1).ToArray()); + var parsedPort = GetPort(values[^1]); - if (parsedPort == 0) - return false; - } - else // [a:b:c] or a:b:c - { - host = endpointString; - port = defaultPort; - } + if (parsedPort == 0) + return false; } + // [a:b:c] or a:b:c else { - return false; + host = endpointString; + port = defaultPort; } if (port == -1) diff --git a/src/AElf.Client/Model/KeyPairInfo.cs b/src/AElf.Client/Model/KeyPairInfo.cs new file mode 100644 index 0000000..cf9f189 --- /dev/null +++ b/src/AElf.Client/Model/KeyPairInfo.cs @@ -0,0 +1,9 @@ +namespace AElf.Client.Model +{ + public class KeyPairInfo + { + public string PrivateKey { get; set; } + public string PublicKey { get; set; } + public string? Address { get; set; } + } +} \ No newline at end of file diff --git a/AElf.Client/Service/HttpService.cs b/src/AElf.Client/Services/HttpService.cs similarity index 68% rename from AElf.Client/Service/HttpService.cs rename to src/AElf.Client/Services/HttpService.cs index 03e9da1..ae69046 100644 --- a/AElf.Client/Service/HttpService.cs +++ b/src/AElf.Client/Services/HttpService.cs @@ -1,37 +1,50 @@ using System; using System.Collections.Generic; +using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; namespace AElf.Client.Service { + public interface IHttpService { - Task GetResponseAsync(string url, string version = null, + Task GetResponseAsync(string url, string? version = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK); - + Task PostResponseAsync(string url, Dictionary parameters, - string version = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK); - - Task DeleteResponseAsObjectAsync(string url, string version = null, - HttpStatusCode expectedStatusCode = HttpStatusCode.OK); + string? version = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, + AuthenticationHeaderValue? authenticationHeaderValue = null); + + Task DeleteResponseAsObjectAsync(string url, string? version = null, + HttpStatusCode expectedStatusCode = HttpStatusCode.OK, + AuthenticationHeaderValue authenticationHeaderValue = null); } - + public class HttpService : IHttpService { private HttpClient Client { get; set; } private int TimeoutSeconds { get; } - + public HttpService(int timeoutSeconds) { TimeoutSeconds = timeoutSeconds; } + + private static T GetResponse(Stream stream) + { + using var streamReader = new StreamReader(stream); + using var reader = new JsonTextReader(streamReader); + var serializer = new JsonSerializer(); + var ret = serializer.Deserialize(reader); + return ret; + } + /// /// Get request. /// @@ -40,14 +53,14 @@ public HttpService(int timeoutSeconds) /// /// /// - public async Task GetResponseAsync(string url, string version = null, + public async Task GetResponseAsync(string url, string? version = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { - var response = await GetResponseAsStringAsync(url, version, expectedStatusCode); - return JsonConvert.DeserializeObject(response, new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }); + var response = await GetResponseAsync(url, version, expectedStatusCode); + await using var stream = await response.Content.ReadAsStreamAsync(); + var ret = GetResponse(stream); + + return ret; } /// @@ -57,19 +70,23 @@ public async Task GetResponseAsync(string url, string version = null, /// /// /// + /// /// /// public async Task PostResponseAsync(string url, Dictionary parameters, - string version = null, - HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + string? version = null, + HttpStatusCode expectedStatusCode = HttpStatusCode.OK, + AuthenticationHeaderValue? authenticationHeaderValue = null) { - var response = await PostResponseAsStringAsync(url, parameters, version, expectedStatusCode); - return JsonConvert.DeserializeObject(response, new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }); - } + var response = await PostResponseAsync(url, parameters, version, true, expectedStatusCode, + authenticationHeaderValue); + + await using var stream = await response.Content.ReadAsStreamAsync(); + var ret = GetResponse(stream); + return ret; + } + /// /// Delete request. /// @@ -79,64 +96,57 @@ public async Task PostResponseAsync(string url, Dictionary /// /// /// - public async Task DeleteResponseAsObjectAsync(string url, string version = null, - HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + public async Task DeleteResponseAsObjectAsync(string url, string? version = null, + HttpStatusCode expectedStatusCode = HttpStatusCode.OK, + AuthenticationHeaderValue authenticationHeaderValue = null) { - var response = await DeleteResponseAsStringAsync(url, version, expectedStatusCode); - return JsonConvert.DeserializeObject(response, new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }); - } + var response = await DeleteResponseAsync(url, version, expectedStatusCode, authenticationHeaderValue); - #region GetResponse + await using var stream = await response.Content.ReadAsStreamAsync(); + var ret = GetResponse(stream); - private async Task GetResponseAsStringAsync(string url, string version = null, - HttpStatusCode expectedStatusCode = HttpStatusCode.OK) - { - var response = await GetResponseAsync(url, version, expectedStatusCode); - return await response.Content.ReadAsStringAsync(); + return ret; } - - private async Task GetResponseAsync(string url, string version = null, + + #region GetResponse + + private async Task GetResponseAsync(string url, string? version = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { version = !string.IsNullOrWhiteSpace(version) ? $";v={version}" : string.Empty; - + var client = GetHttpClient(version); try { var response = await client.GetAsync(url); if (response.StatusCode == expectedStatusCode) return response; - var message = await response.Content.ReadAsStringAsync(); - throw new AElfClientException(message); + throw new AElfClientException(response.ToString()); } catch (Exception ex) { throw new AElfClientException(ex.Message); } } - + #endregion - + #region PostResponse - - private async Task PostResponseAsStringAsync(string url, Dictionary parameters, - string version = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) - { - var response = await PostResponseAsync(url, parameters, version, true, expectedStatusCode); - return await response.Content.ReadAsStringAsync(); - } - + private async Task PostResponseAsync(string url, Dictionary parameters, - string version = null, bool useApplicationJson = false, - HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + string? version = null, bool useApplicationJson = false, + HttpStatusCode expectedStatusCode = HttpStatusCode.OK, + AuthenticationHeaderValue? authenticationHeaderValue = null) { version = !string.IsNullOrWhiteSpace(version) ? $";v={version}" : string.Empty; var client = GetHttpClient(version); - + + if (authenticationHeaderValue != null) + { + client.DefaultRequestHeaders.Authorization = authenticationHeaderValue; + } + HttpContent content; if (useApplicationJson) { @@ -144,14 +154,14 @@ private async Task PostResponseAsync(string url, content = new StringContent(paramsStr, Encoding.UTF8, "application/json"); content.Headers.ContentType = MediaTypeHeaderValue.Parse($"application/json{version}"); } - + else { content = new FormUrlEncodedContent(parameters); content.Headers.ContentType = MediaTypeHeaderValue.Parse($"application/x-www-form-urlencoded{version}"); } - + try { var response = await client.PostAsync(url, content); @@ -165,42 +175,49 @@ private async Task PostResponseAsync(string url, throw new AElfClientException(ex.Message); } } - + #endregion - + #region DeleteResponse - - private async Task DeleteResponseAsStringAsync(string url, string version = null, - HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + + private async Task DeleteResponseAsStringAsync(string url, string? version = null, + HttpStatusCode expectedStatusCode = HttpStatusCode.OK, + AuthenticationHeaderValue authenticationHeaderValue = null) { - var response = await DeleteResponseAsync(url, version, expectedStatusCode); + var response = await DeleteResponseAsync(url, version, expectedStatusCode, authenticationHeaderValue); return await response.Content.ReadAsStringAsync(); } - - private async Task DeleteResponseAsync(string url, string version = null, - HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + + private async Task DeleteResponseAsync(string url, string? version = null, + HttpStatusCode expectedStatusCode = HttpStatusCode.OK, + AuthenticationHeaderValue authenticationHeaderValue = null) { version = !string.IsNullOrWhiteSpace(version) ? $";v={version}" : string.Empty; var client = GetHttpClient(version); + + if (authenticationHeaderValue != null) + { + client.DefaultRequestHeaders.Authorization = authenticationHeaderValue; + } + try { var response = await client.DeleteAsync(url); if (response.StatusCode == expectedStatusCode) return response; - var message = await response.Content.ReadAsStringAsync(); - throw new AElfClientException(message); + throw new AElfClientException(response.ToString()); } catch (Exception ex) { throw new AElfClientException(ex.Message); } } - + #endregion - + #region private methods - - private HttpClient GetHttpClient(string version = null) + + private HttpClient GetHttpClient(string? version = null) { if (Client != null) return Client; Client = new HttpClient @@ -213,7 +230,7 @@ private HttpClient GetHttpClient(string version = null) Client.DefaultRequestHeaders.Add("Connection", "close"); return Client; } - + #endregion } -} \ No newline at end of file +} diff --git a/src/AElf.Client/Services/IBlockAppService.cs b/src/AElf.Client/Services/IBlockAppService.cs new file mode 100644 index 0000000..4697d65 --- /dev/null +++ b/src/AElf.Client/Services/IBlockAppService.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using AElf.Client.Dto; + +namespace AElf.Client.Services +{ + + public interface IBlockAppService + { + Task GetBlockHeightAsync(); + + Task GetBlockByHashAsync(string blockHash, bool includeTransactions = false); + + Task GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false); + } +} diff --git a/src/AElf.Client/Services/IChainAppService.cs b/src/AElf.Client/Services/IChainAppService.cs new file mode 100644 index 0000000..08a06f3 --- /dev/null +++ b/src/AElf.Client/Services/IChainAppService.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AElf.Client.Dto; +using AElf.Kernel; + +namespace AElf.Client +{ + + public interface IChainAppService + { + Task GetChainStatusAsync(); + + Task GetContractFileDescriptorSetAsync(string? address); + + Task> GetTaskQueueStatusAsync(); + + Task GetChainIdAsync(); + } +} diff --git a/src/AElf.Client/Services/IClientService.cs b/src/AElf.Client/Services/IClientService.cs new file mode 100644 index 0000000..c605419 --- /dev/null +++ b/src/AElf.Client/Services/IClientService.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; +using AElf.Client.Model; +using AElf.Types; + +namespace AElf.Client.Services +{ + + public interface IClientService + { + Task IsConnectedAsync(); + Task GetFormattedAddressAsync(Address address); + Task GetGenesisContractAddressAsync(); + Task
GetContractAddressByNameAsync(Hash contractNameHash); + string GetAddressFromPubKey(string pubKey); + KeyPairInfo GenerateKeyPairInfo(); + } +} diff --git a/src/AElf.Client/Services/INetAppService.cs b/src/AElf.Client/Services/INetAppService.cs new file mode 100644 index 0000000..daff3f5 --- /dev/null +++ b/src/AElf.Client/Services/INetAppService.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AElf.Client.Dto; + +namespace AElf.Client.Services +{ + + public interface INetAppService + { + Task AddPeerAsync(string ipAddress, string userName, string password); + + Task RemovePeerAsync(string ipAddress, string userName, string password); + + Task?> GetPeersAsync(bool withMetrics); + + Task GetNetworkInfoAsync(); + } +} diff --git a/src/AElf.Client/Services/ITransactionAppService.cs b/src/AElf.Client/Services/ITransactionAppService.cs new file mode 100644 index 0000000..2c98388 --- /dev/null +++ b/src/AElf.Client/Services/ITransactionAppService.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AElf.Client.Dto; + +namespace AElf.Client.Services +{ + + public interface ITransactionAppService + { + Task GetTransactionPoolStatusAsync(); + + Task ExecuteTransactionAsync(ExecuteTransactionDto input); + + Task ExecuteRawTransactionAsync(ExecuteRawTransactionDto input); + + Task CreateRawTransactionAsync(CreateRawTransactionInput input); + + Task SendRawTransactionAsync(SendRawTransactionInput input); + + Task SendTransactionAsync(SendTransactionInput input); + + Task SendTransactionsAsync(SendTransactionsInput input); + + Task GetTransactionResultAsync(string transactionId); + + Task?> GetTransactionResultsAsync(string blockHash, int offset = 0, + int limit = 10); + + Task GetMerklePathByTransactionIdAsync(string transactionId); + + Task CalculateTransactionFeeAsync(CalculateTransactionFeeInput input); + } +} diff --git a/src/AElf.Client/TransactionBuilder.cs b/src/AElf.Client/TransactionBuilder.cs new file mode 100644 index 0000000..00d088e --- /dev/null +++ b/src/AElf.Client/TransactionBuilder.cs @@ -0,0 +1,63 @@ +using AElf.Cryptography; +using AElf.Types; +using Google.Protobuf; + +namespace AElf.Client +{ + + public class TransactionBuilder + { + private readonly AElfClient _aelfClient; + + private byte[] PrivateKey { get; set; } + private string ContractAddress { get; set; } + private string MethodName { get; set; } + private IMessage Parameter { get; set; } + + public TransactionBuilder(AElfClient aelfClient) + { + _aelfClient = aelfClient; + PrivateKey = ByteArrayHelper.HexStringToByteArray(AElfClientConstants.DefaultPrivateKey); + } + + public TransactionBuilder UsePrivateKey(byte[] privateKey) + { + PrivateKey = privateKey; + return this; + } + + public TransactionBuilder UseSystemContract(string systemContractName) + { + ContractAddress = _aelfClient.GetContractAddressByNameAsync(HashHelper.ComputeFrom(systemContractName)).Result + .ToBase58(); + return this; + } + + public TransactionBuilder UseContract(string contractAddress) + { + ContractAddress = contractAddress; + return this; + } + + public TransactionBuilder UseMethod(string methodName) + { + MethodName = methodName; + return this; + } + + public TransactionBuilder UseParameter(IMessage parameter) + { + Parameter = parameter; + return this; + } + + public Transaction Build() + { + var keyPair = CryptoHelper.FromPrivateKey(PrivateKey); + var from = Address.FromPublicKey(keyPair.PublicKey).ToBase58(); + var unsignedTx = _aelfClient.GenerateTransactionAsync(from, ContractAddress, MethodName, Parameter).Result; + var signedTx = _aelfClient.SignTransaction(PrivateKey, unsignedTx); + return signedTx; + } + } +} diff --git a/src/AElf.KeyStore/AElf.KeyStore.csproj b/src/AElf.KeyStore/AElf.KeyStore.csproj new file mode 100644 index 0000000..c7dc814 --- /dev/null +++ b/src/AElf.KeyStore/AElf.KeyStore.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + enable + enable + AElf.KeyStore + + + + + + + + \ No newline at end of file diff --git a/src/AElf.KeyStore/AElfKeyStoreService.cs b/src/AElf.KeyStore/AElfKeyStoreService.cs new file mode 100644 index 0000000..f1021b8 --- /dev/null +++ b/src/AElf.KeyStore/AElfKeyStoreService.cs @@ -0,0 +1,24 @@ +using AElf.Cryptography; +using AElf.Types; +using Nethereum.KeyStore; + +namespace AElf.KeyStore; + +public class AElfKeyStoreService : KeyStoreService +{ + + public string EncryptKeyStoreAsJson(string password, string privateKey) + { + var keyPair = CryptoHelper.FromPrivateKey(ByteArrayHelper.HexStringToByteArray(privateKey)); + var address = Address.FromPublicKey(keyPair.PublicKey); + return EncryptAndGenerateDefaultKeyStoreAsJson(password, keyPair.PrivateKey, address.ToBase58()); + } + + public byte[] DecryptKeyStoreFromFile(string password, string filePath) + { + using var file = File.OpenText(filePath); + var json = file.ReadToEnd(); + return DecryptKeyStoreFromJson(password, json); + } + +} \ No newline at end of file diff --git a/AElf.Client.Test/AElf.Client.Test.csproj b/test/AElf.Client.Test/AElf.Client.Test.csproj similarity index 59% rename from AElf.Client.Test/AElf.Client.Test.csproj rename to test/AElf.Client.Test/AElf.Client.Test.csproj index 7e630c7..f6a8729 100644 --- a/AElf.Client.Test/AElf.Client.Test.csproj +++ b/test/AElf.Client.Test/AElf.Client.Test.csproj @@ -1,21 +1,20 @@ - netcoreapp3.0 + net6.0 false - - - + + - - + + - + diff --git a/test/AElf.Client.Test/ClientTest.cs b/test/AElf.Client.Test/ClientTest.cs new file mode 100644 index 0000000..f4c63df --- /dev/null +++ b/test/AElf.Client.Test/ClientTest.cs @@ -0,0 +1,603 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using AElf.Cryptography; +using AElf.Types; +using AElf.Client.Dto; +using AElf.Client.Extensions; +using AElf.Client.Service; +using AElf.Contracts.MultiToken; +using Google.Protobuf; +using Google.Protobuf.WellKnownTypes; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Shouldly; +using Volo.Abp.Threading; +using Xunit; +using Xunit.Abstractions; +using Address = AElf.Types.Address; +using Hash = AElf.Types.Hash; + +namespace AElf.Client.Test; + +public class ClientTest +{ + private const string BaseUrl = "http://127.0.0.1:8000"; + + private string _genesisAddress; + private string GenesisAddress => GetGenesisContractAddress(); + + // example contract-method-name + private string ContractMethodName => "GetContractAddressByName"; + + // Address and privateKey of a node. + private readonly string _address; + private const string PrivateKey = "cd86ab6347d8e52bbbe8532141fc59ce596268143a308d1d40fedf385528b458"; + + private AElfClient Client { get; } + private readonly ITestOutputHelper _testOutputHelper; + + private const string UserName = "test1"; + private const string Password = "test"; + private const string Version = "1.2.3.0"; + + public ClientTest(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + Client = new AElfClient(BaseUrl, userName: UserName, password: Password); + + // To get address from privateKey.s + _address = Client.GetAddressFromPrivateKey(PrivateKey); + } + + #region block + + [Fact] + public async Task GetBlockHeightTest() + { + var height = await Client.GetBlockHeightAsync(); + height.ShouldBeGreaterThanOrEqualTo(1); + _testOutputHelper.WriteLine(height.ToString()); + } + + [Fact] + public async Task GetBlock_Test() + { + var height = await Client.GetBlockHeightAsync(); + var blockByHeight = await Client.GetBlockByHeightAsync(height); + var blockByHash = await Client.GetBlockByHashAsync(blockByHeight.BlockHash); + + var blockByHeightSerialized =JsonConvert.SerializeObject(blockByHeight, Formatting.Indented); + var blockByHashSerialized =JsonConvert.SerializeObject(blockByHash, Formatting.Indented); + + blockByHeightSerialized.ShouldBe(blockByHashSerialized); + blockByHeight.Header.Height.ShouldBe(height); + blockByHeight.IsComplete().ShouldBeTrue(); + + var block = JsonConvert.SerializeObject(blockByHeight, Formatting.Indented); + _testOutputHelper.WriteLine(block); + } + + [Fact] + public async Task GetBlockByHeight_Failed_Test() + { + const int timeOut = 60; + var httpService = new HttpService(timeOut); + const int heightNotExist = int.MaxValue; + var errorResponse = await httpService.GetResponseAsync( + $"{BaseUrl}/api/blockChain/blockByHeight?blockHeight={heightNotExist}&includeTransactions=false", + expectedStatusCode: HttpStatusCode.Forbidden); + errorResponse.Error.Code.ShouldBe(Error.NotFound.ToString()); + errorResponse.Error.Message.ShouldBe(Error.Message[Error.NotFound]); + var str = JsonConvert.SerializeObject(errorResponse, Formatting.Indented); + _testOutputHelper.WriteLine(str); + } + + #endregion + + #region chain + + [Fact] + public async Task GetChainStatus_Test() + { + var chainStatusDto = await Client.GetChainStatusAsync(); + + chainStatusDto.Branches.Count.ShouldBeGreaterThanOrEqualTo(1); + chainStatusDto.Branches.First().Key.ShouldNotBeNullOrWhiteSpace(); + chainStatusDto.Branches.First().Value.ShouldBeGreaterThanOrEqualTo(1); + chainStatusDto.ChainId.ShouldNotBeNullOrWhiteSpace(); + chainStatusDto.BestChainHash.ShouldNotBeNullOrWhiteSpace(); + chainStatusDto.BestChainHeight.ShouldBeGreaterThanOrEqualTo(1); + chainStatusDto.GenesisBlockHash.ShouldNotBeNullOrWhiteSpace(); + chainStatusDto.GenesisContractAddress.ShouldNotBeNullOrWhiteSpace(); + chainStatusDto.LongestChainHash.ShouldNotBeNullOrWhiteSpace(); + chainStatusDto.LongestChainHeight.ShouldBeGreaterThanOrEqualTo(1); + chainStatusDto.LastIrreversibleBlockHash.ShouldNotBeNullOrWhiteSpace(); + chainStatusDto.LastIrreversibleBlockHeight.ShouldBeGreaterThanOrEqualTo(1); + + var chainStatus = JsonConvert.SerializeObject(chainStatusDto, Formatting.Indented); + _testOutputHelper.WriteLine(chainStatus); + } + + #endregion + + #region net + + /// + /// Work in multiple nodes.(>=2) + /// + /// + [Fact(Skip = "Redo this later.")] + public async Task AddPeer_Test() + { + // add ipAddress + var addressToAdd = "192.168.199.122:7003"; + + var addSuccess = await Client.AddPeerAsync(addressToAdd, UserName, Password); + addSuccess.ShouldBeTrue(); + _testOutputHelper.WriteLine($"Added ipAddress: {addressToAdd}"); + } + + [Fact(Skip = "Redo this later.")] + public async Task RemovePeer_Test() + { + var peers = await Client.GetPeersAsync(false); + peers.ShouldNotBeEmpty(); + + var peerToRemoveAddress = peers[0].IpAddress; + var removeSuccess = await Client.RemovePeerAsync(peerToRemoveAddress, UserName, Password); + Assert.True(removeSuccess); + _testOutputHelper.WriteLine($"Removed ipAddress: {peerToRemoveAddress}"); + } + + [Fact] + public async Task GetPeers_Test() + { + var peers = await Client.GetPeersAsync(false); + Assert.True(peers != null); + var peersInfo = JsonConvert.SerializeObject(peers, Formatting.Indented); + _testOutputHelper.WriteLine(peersInfo); + } + + [Fact] + public async Task GetNetworkInfo_Test() + { + var netWorkInfo = await Client.GetNetworkInfoAsync(); + Assert.True(netWorkInfo != null); + netWorkInfo.Version.ShouldBe(Version); + var info = JsonConvert.SerializeObject(netWorkInfo, Formatting.Indented); + _testOutputHelper.WriteLine(info); + } + + #endregion + + #region transaction + + [Fact] + public async Task GetTaskQueueStatus_Test() + { + var taskQueueStatus = await Client.GetTaskQueueStatusAsync(); + taskQueueStatus.ShouldNotBeEmpty(); + + var queueStatus = JsonConvert.SerializeObject(taskQueueStatus, Formatting.Indented); + _testOutputHelper.WriteLine(queueStatus); + } + + [Fact] + public async Task GetTransactionPoolStatus_Test() + { + var poolStatus = await Client.GetTransactionPoolStatusAsync(); + Assert.True(poolStatus != null); + + var status = JsonConvert.SerializeObject(poolStatus, Formatting.Indented); + _testOutputHelper.WriteLine(status); + } + + [Fact] + public async Task ExecuteTransaction_Test() + { + var toAddress = await Client.GetContractAddressByNameAsync(HashHelper.ComputeFrom("AElf.ContractNames.Token")); + var methodName = "GetNativeTokenInfo"; + var param = new Empty(); + + var transaction = await Client.GenerateTransactionAsync(_address, toAddress.ToBase58(), methodName, param); + var txWithSign = Client.SignTransaction(PrivateKey, transaction); + + var transactionResult = await Client.ExecuteTransactionAsync(new ExecuteTransactionDto + { + RawTransaction = txWithSign.ToByteArray().ToHex() + }); + Assert.True(transactionResult != null); + + var tokenInfo = TokenInfo.Parser.ParseFrom(ByteArrayHelper.HexStringToByteArray(transactionResult)); + Assert.True(tokenInfo.Symbol == "ELF"); + } + + [Fact] + public async Task CreateRawTransaction_Test() + { + var address = GenesisAddress; + var status = await Client.GetChainStatusAsync(); + var height = status.BestChainHeight; + var blockHash = status.BestChainHash; + + var createRaw = await Client.CreateRawTransactionAsync(new CreateRawTransactionInput + { + From = _address, + To = address, + MethodName = ContractMethodName, + Params = new JObject + { + ["value"] = HashHelper.ComputeFrom("AElf.ContractNames.Token").Value.ToBase64() + }.ToString(), + RefBlockNumber = height, + RefBlockHash = blockHash + }); + + createRaw.RawTransaction.ShouldNotBeEmpty(); + } + + [Fact] + public async Task ExecuteRawTransaction_Test() + { + var address = GenesisAddress; + var status = await Client.GetChainStatusAsync(); + var height = status.BestChainHeight; + var blockHash = status.BestChainHash; + + var createRaw = await Client.CreateRawTransactionAsync(new CreateRawTransactionInput + { + From = _address, + To = address, + MethodName = ContractMethodName, + Params = new JObject + { + ["value"] = HashHelper.ComputeFrom("AElf.ContractNames.Consensus").Value.ToBase64() + }.ToString(), + RefBlockNumber = height, + RefBlockHash = blockHash + }); + + var transactionId = HashHelper.ComputeFrom(ByteArrayHelper.HexStringToByteArray(createRaw.RawTransaction)); + var signature = GetSignatureWith(PrivateKey, transactionId.ToByteArray()).ToHex(); + var rawTransactionResult = await Client.ExecuteRawTransactionAsync(new ExecuteRawTransactionDto + { + RawTransaction = createRaw.RawTransaction, + Signature = signature + }); + + rawTransactionResult.ShouldNotBeEmpty(); + var consensusAddress = + (await Client.GetContractAddressByNameAsync(HashHelper.ComputeFrom("AElf.ContractNames.Consensus"))) + .ToBase58(); + + var addressResult = rawTransactionResult.Trim('"'); + _testOutputHelper.WriteLine(rawTransactionResult); + addressResult.ShouldBe(consensusAddress); + } + + [Fact] + public async Task SendRawTransaction_Test() + { + var toAddress = GenesisAddress; + var status = await Client.GetChainStatusAsync(); + var height = status.BestChainHeight; + var blockHash = status.BestChainHash; + + var createRaw = await Client.CreateRawTransactionAsync(new CreateRawTransactionInput + { + From = _address, + To = toAddress, + MethodName = ContractMethodName, + Params = new JObject + { + ["value"] = HashHelper.ComputeFrom("AElf.ContractNames.Token").Value.ToBase64() + }.ToString(), + RefBlockNumber = height, + RefBlockHash = blockHash + }); + createRaw.RawTransaction.ShouldNotBeEmpty(); + + var transactionId = HashHelper.ComputeFrom(ByteArrayHelper.HexStringToByteArray(createRaw.RawTransaction)); + var signature = GetSignatureWith(PrivateKey, transactionId.ToByteArray()).ToHex(); + + var rawTransactionResult = await Client.SendRawTransactionAsync(new SendRawTransactionInput + { + Transaction = createRaw.RawTransaction, + Signature = signature, + ReturnTransaction = true + }); + + rawTransactionResult.ShouldNotBeNull(); + rawTransactionResult.Transaction.ShouldNotBeNull(); + rawTransactionResult.TransactionId.ShouldNotBeNullOrWhiteSpace(); + + var result = JsonConvert.SerializeObject(rawTransactionResult, Formatting.Indented); + _testOutputHelper.WriteLine(result); + } + + [Fact] + public async Task SendTransaction_Test() + { + var toAddress = GenesisAddress; + var methodName = ContractMethodName; + var param = HashHelper.ComputeFrom("AElf.ContractNames.Vote"); + + var transaction = await Client.GenerateTransactionAsync(_address, toAddress, methodName, param); + var txWithSign = Client.SignTransaction(PrivateKey, transaction); + + var result = await Client.SendTransactionAsync(new SendTransactionInput + { + RawTransaction = txWithSign.ToByteArray().ToHex() + }); + + result.ShouldNotBeNull(); + result.TransactionId.ShouldNotBeNull(); + _testOutputHelper.WriteLine(result.TransactionId); + } + + [Fact] + public async Task SendTransactions_Test() + { + var toAddress = GenesisAddress; + var methodName = ContractMethodName; + var param1 = HashHelper.ComputeFrom("AElf.ContractNames.Token"); + var param2 = HashHelper.ComputeFrom("AElf.ContractNames.Vote"); + + var parameters = new List {param1, param2}; + var sb = new StringBuilder(); + + foreach (var param in parameters) + { + var tx = await Client.GenerateTransactionAsync(_address, toAddress, methodName, param); + var txWithSign = Client.SignTransaction(PrivateKey, tx); + sb.Append(txWithSign.ToByteArray().ToHex() + ','); + } + + var result1 = await Client.SendTransactionsAsync(new SendTransactionsInput + { + RawTransactions = sb.ToString().Substring(0, sb.Length - 1) + }); + + Assert.True(result1 != null); + result1.Length.ShouldBe(2); + _testOutputHelper.WriteLine(JsonConvert.SerializeObject(result1)); + + } + + [Fact] + public async Task GetTransactionResult_Test() + { + var firstBlockDto = await Client.GetBlockByHeightAsync(1, true); + var transactionId = firstBlockDto.Body.Transactions.FirstOrDefault(); + + var transactionResultDto = await Client.GetTransactionResultAsync(transactionId); + Assert.True(transactionResultDto.Status == TransactionResultStatus.Mined.ToString().ToUpper()); + } + + [Fact] + public async Task GetTransactionResults_Test() + { + var firstBlockDto = await Client.GetBlockByHeightAsync(1, true); + var blockHash = firstBlockDto.BlockHash; + + var transactionResults = await Client.GetTransactionResultsAsync(blockHash, 0, 2); + foreach (var transaction in transactionResults) + { + Assert.True(transaction.Status == TransactionResultStatus.Mined.ToString().ToUpper()); + } + } + + [Fact] + public async Task GetMerklePathByTransactionId_Test() + { + var firstBlockDto = await Client.GetBlockByHeightAsync(1, true); + var transactionId = firstBlockDto.Body.Transactions.FirstOrDefault(); + var merklePathDto = await Client.GetMerklePathByTransactionIdAsync(transactionId); + Assert.True(merklePathDto != null); + + var merklePath = JsonConvert.SerializeObject(merklePathDto, Formatting.Indented); + merklePath.ShouldNotBeEmpty(); + + _testOutputHelper.WriteLine(merklePath); + } + + [Fact] + public async Task GetChainId_Test() + { + var chainId = await Client.GetChainIdAsync(); + chainId.ShouldBe(9992731); + } + + [Fact] + public async Task IsConnected_Test() + { + var isConnected = await Client.IsConnectedAsync(); + isConnected.ShouldBeTrue(); + } + + [Fact] + public async Task GetGenesisContractAddress_Test() + { + var genesisAddress = await Client.GetGenesisContractAddressAsync(); + genesisAddress.ShouldNotBeEmpty(); + + var address = await Client.GetContractAddressByNameAsync(Hash.Empty); + var genesisAddress2 = address.ToBase58(); + Assert.True(genesisAddress == genesisAddress2); + } + + [Fact] + public async Task GetFormattedAddress_Test() + { + var result = await Client.GetFormattedAddressAsync(Address.FromBase58(_address)); + _testOutputHelper.WriteLine(result); + Assert.True(result == $"ELF_{_address}_AELF"); + } + + [Fact] + public void GetNewKeyPairInfo_Test() + { + var output = Client.GenerateKeyPairInfo(); + var addressOutput = JsonConvert.SerializeObject(output); + _testOutputHelper.WriteLine(addressOutput); + } + + [Fact] + public async Task Transfer_Test() + { + var toAccount = Client.GenerateKeyPairInfo().Address; + var toAddress = await Client.GetContractAddressByNameAsync(HashHelper.ComputeFrom("AElf.ContractNames.Token")); + var methodName = "Transfer"; + var param = new TransferInput + { + To = new Address {Value = Address.FromBase58(toAccount).Value}, + Symbol = "ELF", + Amount = 1000 + }; + + var transaction = await Client.GenerateTransactionAsync(_address, toAddress.ToBase58(), methodName, param); + var txWithSign = Client.SignTransaction(PrivateKey, transaction); + + var result = await Client.SendTransactionAsync(new SendTransactionInput + { + RawTransaction = txWithSign.ToByteArray().ToHex() + }); + + result.ShouldNotBeNull(); + _testOutputHelper.WriteLine(result.TransactionId); + + await Task.Delay(4000); + var transactionResult = await Client.GetTransactionResultAsync(result.TransactionId); + transactionResult.Status.ShouldBe(TransactionResultStatus.Mined.ToString().ToUpper()); + var transactionFees = transactionResult.GetTransactionFees(); + transactionFees.First().Key.ShouldBe("ELF"); + transactionFees.First().Value.ShouldBeGreaterThan(0L); + _testOutputHelper.WriteLine(JsonConvert.SerializeObject(transactionFees, Formatting.Indented)); + + var paramGetBalance = new GetBalanceInput + { + Symbol = "ELF", + Owner = new Address {Value = Address.FromBase58(toAccount).Value} + }; + + var transactionGetBalance = + await Client.GenerateTransactionAsync(_address, toAddress.ToBase58(), "GetBalance", paramGetBalance); + var txWithSignGetBalance = Client.SignTransaction(PrivateKey, transactionGetBalance); + + var transactionGetBalanceResult = await Client.ExecuteTransactionAsync(new ExecuteTransactionDto + { + RawTransaction = txWithSignGetBalance.ToByteArray().ToHex() + }); + Assert.True(transactionResult != null); + + var balance = + GetBalanceOutput.Parser.ParseFrom(ByteArrayHelper.HexStringToByteArray(transactionGetBalanceResult)); + balance.Balance.ShouldBe(1000L); + } + + [Fact] + public void GetTransactionFee_Test() + { + var transactionResultDto = new TransactionResultDto + { + Logs = new[] + { + new LogEventDto + { + Name = "TransactionFeeCharged", + NonIndexed = Convert.ToBase64String((new TransactionFeeCharged {Symbol = "ELF", Amount = 1000}).ToByteArray()) + }, + new LogEventDto + { + Name = "ResourceTokenCharged", + NonIndexed = Convert.ToBase64String((new ResourceTokenCharged {Symbol = "READ", Amount = 800}).ToByteArray()) + }, + new LogEventDto + { + Name = "ResourceTokenCharged", + NonIndexed = Convert.ToBase64String((new ResourceTokenCharged {Symbol = "WRITE", Amount = 600}).ToByteArray()) + }, + new LogEventDto + { + Name = "ResourceTokenOwned", + NonIndexed = Convert.ToBase64String((new ResourceTokenOwned {Symbol = "READ", Amount = 200}).ToByteArray()) + } + } + }; + + var transactionFees = transactionResultDto.GetTransactionFees(); + transactionFees.Count.ShouldBe(3); + transactionFees["ELF"].ShouldBe(1000); + transactionFees["READ"].ShouldBe(800); + transactionFees["WRITE"].ShouldBe(600); + + + transactionResultDto = new TransactionResultDto(); + transactionFees = transactionResultDto.GetTransactionFees(); + transactionFees.Count.ShouldBe(0); + } + + [Fact] + public async void CalculateTransactionFee_Test() + { + var address = GenesisAddress; + var status = await Client.GetChainStatusAsync(); + var height = status.BestChainHeight; + var blockHash = status.BestChainHash; + + var createRaw = await Client.CreateRawTransactionAsync(new CreateRawTransactionInput + { + From = _address, + To = address, + MethodName = ContractMethodName, + Params = new JObject + { + ["value"] = HashHelper.ComputeFrom("AElf.ContractNames.Token").Value.ToBase64() + }.ToString(), + RefBlockNumber = height, + RefBlockHash = blockHash + }); + + createRaw.RawTransaction.ShouldNotBeEmpty(); + var input = new CalculateTransactionFeeInput + { + RawTransaction = createRaw.RawTransaction + }; + var calculateTransactionFeeOutput = await Client.CalculateTransactionFeeAsync(input); + calculateTransactionFeeOutput.Success.ShouldBe(true); + calculateTransactionFeeOutput.TransactionFee["ELF"].ShouldBeGreaterThan(18000000); + calculateTransactionFeeOutput.TransactionFee["ELF"].ShouldBeLessThanOrEqualTo(19000000); + + + + + } + + #endregion + + #region private methods + + private string GetGenesisContractAddress() + { + if (_genesisAddress != null) return _genesisAddress; + + var statusDto = AsyncHelper.RunSync(Client.GetChainStatusAsync); + _genesisAddress = statusDto.GenesisContractAddress; + + return _genesisAddress; + } + + private ByteString GetSignatureWith(string privateKey, byte[] txData) + { + // Sign the hash + var signature = CryptoHelper.SignWithPrivateKey(ByteArrayHelper.HexStringToByteArray(privateKey), txData); + return ByteString.CopyFrom(signature); + } + + #endregion +} \ No newline at end of file diff --git a/test/AElf.Client.Test/Extensions.cs b/test/AElf.Client.Test/Extensions.cs new file mode 100644 index 0000000..3d5b172 --- /dev/null +++ b/test/AElf.Client.Test/Extensions.cs @@ -0,0 +1,43 @@ +using System; +using AElf.Client.Dto; + +namespace AElf.Client.Test +{ + public static class Extensions + { + public static bool IsComplete(this BlockDto block) + { + if (block == null + || block.BlockHash.IsNullOrWhiteSpace() + || block.Header == null + || block.Header.Bloom.IsNullOrWhiteSpace() + || block.Header.Extra.IsNullOrWhiteSpace() + || block.Header.Height <= 0 + || block.Header.SignerPubkey.IsNullOrWhiteSpace() + || block.Header.ChainId.IsNullOrWhiteSpace() + || block.Header.PreviousBlockHash.IsNullOrWhiteSpace() + || block.Header.MerkleTreeRootOfTransactions.IsNullOrWhiteSpace() + || block.Header.MerkleTreeRootOfTransactionState.IsNullOrWhiteSpace() + || block.Header.MerkleTreeRootOfWorldState.IsNullOrWhiteSpace() + || block.Body == null + || block.Body.TransactionsCount == 0) + { + return false; + } + + return true; + } + + public static bool IsCompleteWithTransaction(this BlockDto block) + { + if (!block.IsComplete() + || block.Body.Transactions == null + || block.Body.Transactions.Count != block.Body.TransactionsCount) + { + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/AElf.Client.Test/WebAppErrorResponse.cs b/test/AElf.Client.Test/WebAppErrorResponse.cs similarity index 100% rename from AElf.Client.Test/WebAppErrorResponse.cs rename to test/AElf.Client.Test/WebAppErrorResponse.cs diff --git a/test/AElf.KeyStore.Tests/AElf.KeyStore.Tests.csproj b/test/AElf.KeyStore.Tests/AElf.KeyStore.Tests.csproj new file mode 100644 index 0000000..d823e62 --- /dev/null +++ b/test/AElf.KeyStore.Tests/AElf.KeyStore.Tests.csproj @@ -0,0 +1,33 @@ + + + + net6.0 + enable + enable + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + Always + + + + \ No newline at end of file diff --git a/test/AElf.KeyStore.Tests/AElfKeyStoreServiceTests.cs b/test/AElf.KeyStore.Tests/AElfKeyStoreServiceTests.cs new file mode 100644 index 0000000..9377014 --- /dev/null +++ b/test/AElf.KeyStore.Tests/AElfKeyStoreServiceTests.cs @@ -0,0 +1,65 @@ +// ReSharper disable StringLiteralTypo + +using Xunit; + +namespace AElf.KeyStore.Tests; + +public class AElfKeyStoreServiceTests +{ + private const string Password = "abcde"; + private const string PrivateKeyHex = "ff96c3463af0b8629f170f078f97ac0147490b92e1784e3bff93f7ee9d1abcb6"; + + [Fact] + public void EncryptKeyStoreAsJson_Test() + { + var keystoreService = new AElfKeyStoreService(); + var keystoreJson = keystoreService.EncryptKeyStoreAsJson( + Password, + PrivateKeyHex + ); + Assert.Contains("\"address\":\"VQFq9atg4fMtFLhqpVh48ZnhX8FXMGBHW8MDANPpCSHcZisU6\"", keystoreJson); + var privateKey = keystoreService.DecryptKeyStoreFromJson(Password, keystoreJson); + Assert.Equal(ByteArrayHelper.HexStringToByteArray(PrivateKeyHex), privateKey); + } + + [Fact] + public void DecryptKeyStoreFromJson_Test() + { + const string jsonKeyStore = + @" + { + ""crypto"": { + ""cipher"": ""aes-128-ctr"", + ""ciphertext"": ""1734a897caeea53e306fa6908fca443e598ea1cb6361fb27e5c45de61a26eb25"", + ""cipherparams"": { + ""iv"": ""36f00104f0488386db1f3e3d37b14bfe"" + }, + ""kdf"": ""scrypt"", + ""mac"": ""011ff2bee41f29f8fb6f7a63b1266bf04054bf1881e94cd3a77ead034ec47892"", + ""kdfparams"": { + ""n"": 262144, + ""r"": 1, + ""p"": 8, + ""dklen"": 32, + ""salt"": ""fd09ae033a9660eb1ad6a0bb0bf7b03ee30944c2fe621eef2a262fd3d2a92881"" + } + }, + ""id"": ""7b2aa039-291d-4e09-8f18-8d503fd7711a"", + ""address"": ""VQFq9atg4fMtFLhqpVh48ZnhX8FXMGBHW8MDANPpCSHcZisU6"", + ""version"": 3 + } + "; + var keystoreService = new AElfKeyStoreService(); + var privateKey = keystoreService.DecryptKeyStoreFromJson(Password, jsonKeyStore); + Assert.Equal(ByteArrayHelper.HexStringToByteArray(PrivateKeyHex), privateKey); + } + + [Fact] + public void DecryptKeyStoreFromFile_Test() + { + var keystoreService = new AElfKeyStoreService(); + var privateKey = keystoreService.DecryptKeyStoreFromFile(Password, "data/test.json"); + Assert.Equal(ByteArrayHelper.HexStringToByteArray(PrivateKeyHex), privateKey); + } + +} \ No newline at end of file diff --git a/test/AElf.KeyStore.Tests/data/test.json b/test/AElf.KeyStore.Tests/data/test.json new file mode 100644 index 0000000..14dcccc --- /dev/null +++ b/test/AElf.KeyStore.Tests/data/test.json @@ -0,0 +1,21 @@ +{ + "crypto": { + "cipher": "aes-128-ctr", + "ciphertext": "1734a897caeea53e306fa6908fca443e598ea1cb6361fb27e5c45de61a26eb25", + "cipherparams": { + "iv": "36f00104f0488386db1f3e3d37b14bfe" + }, + "kdf": "scrypt", + "mac": "011ff2bee41f29f8fb6f7a63b1266bf04054bf1881e94cd3a77ead034ec47892", + "kdfparams": { + "n": 262144, + "r": 1, + "p": 8, + "dklen": 32, + "salt": "fd09ae033a9660eb1ad6a0bb0bf7b03ee30944c2fe621eef2a262fd3d2a92881" + } + }, + "id": "7b2aa039-291d-4e09-8f18-8d503fd7711a", + "address": "VQFq9atg4fMtFLhqpVh48ZnhX8FXMGBHW8MDANPpCSHcZisU6", + "version": 3 +} \ No newline at end of file