Introduction to Nethereum Blockchain in DotNetCore



Comments



Description

Introduction to Nethereum Blockchain in dotNetCoreThis article describes the process of using a blockchain platform like Ethereum in dotNet core. The target audience are other dotNet developers who want to start with Ethereum. Understanding of blockchain is needed. In this article we construct a full example that allows you to interact with a custom written smart contract. The first era of blockchain can be viewed as Bitcoin only and no smart contracts. Nevertheless, the second era of blockchain is showing to be more promising. With more blockchain platforms besides Bitcoin, it’s showing more mature and blockchains have more possibilities. The Ethereum blockchain is more a distributed ledger with smart contracts which uses a crypto currency. The focus of Ethereum is more on the smart contract part, then on crypto currency. The purpose of Ether (Ethereum’s crypto currency) is to give pay for executing transactions which can be mining contracts or executing contracts. A smart contract is a piece of code written for the Ethereum Virtual Machine. This can be written in Solidity and compiled to byte code. This byte code is put in the ledger and becomes immutable but still can be interacted with, and can have changing states. As Ethereum documentation puts it “From a practical standpoint, the EVM can be thought of as a large decentralized computer containing millions of objects, called "accounts", which have the ability to maintain an internal database, execute code and talk to each other.” From a developer standpoint, you can view Solidity as a Javascript like language, which is a bit limited. Since the Solidity code runs in a blockchain there are good reasons for it to be so limited. Something simple as random numbers are a bit of a challenge. Also getting data with a Http call isn’t possible because the truth needs to lie in the system. Still you can call contracts and put in data to change states, so external influence is possible. First of all install the Mist browser and Geth. The Mist browser is a GUI which acts as a wallet for your Ether. Geth is the program-interface which your code connects to, to which Geth connects to the blockchain of Ethereum. For this article, we will be using the testnet. This way we can mine some Ether for free. When Mist has been started, select using the test net from the menu. Create an account and mine some coins (menu item Develop and start mining) NET Core Web Application” and then chose the Web. So start your installed Geth in a console. Since the IPC implementation is only supported on Windows. open Visual Studio and create a new project. The first two are for Ethereum the last for table storage. it’s fast and cheap. This is important because we. We have chosen to make the system persistent with Azure Table storage. the Mist browser and other applications are going to access this with IPC or RPC. Nethereum. Only it’s not possible to start mining because the standalone Geth is running. We’re going to create a service with some methods to interact with the blockchain and release a contract to the blockchain. Now it’s time to start developing.1".0. "Nethereum.Storage": "8. This coin piggybank contract will store our coin balance. “\Program Files\Geth\geth” --testnet --rpcapi eth. "WindowsAzure.1. The BouncyCastle is a crypto library needed for Nethereum.json.Web3 is the whole library for accessing your local Geth process through RPC json. Now let’s close the wallet otherwise you can’t open a new geth process.1.API template. This comes in handy when doing transactions. Nothing epic and surely not a full application but it’s nice to see what we can do.BouncyCastle": "1. We stick to web3 RPC in our solution. And we see that’s picking up the current blockchain cache and it has the http endpoint listening on localhost:8545.personal --rpc Above the result of our command. Now you can open the wallet again. we can’t use this in dotNetCore. Create a “ASP.0-rc1". After the contract is mined we can call the methods of contract. "Portable. Even releasing a contract or executing a contract costs ether.Web3": "2.web3.After some time.1" Save and watch the packages being restored. .8. First add these dependencies to your Project. you will have some Ether. Please note that the code is available at our Github. Tasks. Abi = abi.Models. Task<Contract> GetContract(string name). string bytecode. Task<bool> ReleaseContract(string name. mainly for security/immutable reasons. } } } Now create a folder with the name Services and create file IEthereumService the interface so we can use it for Dependency Injection. } } . } public string ContractAddress { get. string abi. set. } public EthereumContractInfo() { } public EthereumContractInfo(string name. Once the contract is put into the blockchain it cannot be changed or Solidity code cannot be retrieved. using Nethereum.WindowsAzure. namespace EthereumStart. Bytecode = bytecode. using EthereumStart. set. Ethereum doesn’t have any options for getting contracts back out of the blockchain.Threading. TransactionHash = transactionHash. namespace EthereumStart. int gas). string transactionHash) { PartitionKey = "contract". Create a file called EthereumContractInfo derived from Azure Storage class TableEntity in your model folder.Models { public class EthereumContractInfo : TableEntity { public string Abi { get.First we need a model to capture our Ethereum Contract State.Contracts. using System. Task<EthereumContractInfo> GetContractFromTableStorage(string name).Storage. } Task<bool> SaveContractToTableStorage(EthereumContractInfo contract). string byteCode. using Microsoft.Table. string abi. set. RowKey = name. set. Task<string> TryGetContractAddress(string name). Task<decimal> GetBalance(string address). That’s why we need to store this information in our system. set.Services { public interface IEthereumService { string AccountAddress { get. } public string Bytecode { get. } public string TransactionHash { get. Storage. await tableRef. using System.Storage.Extensions.WindowsAzure. var tableRef = client. using System. _storageKey).Value. } public async Task<bool> SaveContractToTableStorage(EthereumContractInfo contract) { StorageCredentials credentials = new StorageCredentials(_storageAccount. _storageKey = config. public string AccountAddress { get { return _accountAddress. _password = config. private string _accountAddress. namespace EthereumStart. private string _password. Now we create the file BasicEthereumService to implement the interface. using Nethereum.Models.All methods should return a task because we want to make the implementation to use async. The idea is that we going to release the contract. } set { _accountAddress = value. } } public BasicEthereumService(IOptions<EthereumSettings> config) { _web3 = new Web3("http://localhost:8545"). using Microsoft. _storageAccount = config.Web3 _web3. try to get it’s address and then invoke it’s methods on that address.CreateCloudTableClient().StorageKey. private string _storageKey.WindowsAzure.Contracts.Web3.Web3.EhtereumAccount.Storage. var client = account. TableOperation ops = TableOperation. private string _storageAccount.GetTableReference("ethtransactions").Auth. . _accountAddress = config.Services { public class BasicEthereumService : IEthereumService { private Nethereum.Tasks.Value.Value.Value. using Microsoft. true).Table. using Microsoft. CloudStorageAccount account = new CloudStorageAccount(credentials.InsertOrMerge(contract).Options.EhtereumPassword. using Microsoft. using EthereumStart.StorageAccount. using Nethereum.Threading.CreateIfNotExistsAsync().WindowsAzure. SendRequestAsync(address).Convert. _accountAddress. await tableRef. int gas) { // check contractName var existing = await this. abi.SendRequestAsync(abi.Eth.UnlockAccount. var client = account.FromWei(balance. name). byteCode.ExecuteAsync(ops). _password. return _web3.ExecuteAsync(ops). } public async Task<bool> ReleaseContract(string name.GetTableReference("ethtransactions"). else return null. new Nethereum.DeployContract.HexTypes. EthereumContractInfo eci = new EthereumContractInfo(name. } public async Task<EthereumContractInfo> GetContractFromTableStorage(string name) { StorageCredentials credentials = new StorageCredentials(_storageAccount.CreateCloudTableClient().Personal. . byteCode. 60). } return false.Hex. await tableRef.HexBigInteger(gas). true). var tableRef = client.GetBalance.SendRequestAsync(_accountAddress.Result. transactionHash). 2). TableOperation ops = TableOperation.HttpStatusCode == 200) return (EthereumContractInfo)tableResult.Value. if (resultUnlocking) { var transactionHash = await _web3.CreateIfNotExistsAsync(). return true. var tableResult = await tableRef. CloudStorageAccount account = new CloudStorageAccount(credentials. string abi. string byteCode. return await SaveContractToTableStorage(eci). if (tableResult.Retrieve<EthereumContractInfo>("contract".GetContractFromTableStorage(name). } public async Task<decimal> GetBalance(string address) { var balance = await _web3. _storageKey). } } catch (Exception exc) { return false. 18).Eth. try { var resultUnlocking = await _web3. if (existing != null) throw new Exception($"Contract {name} is present in storage"). if (existing == null) throw new Exception($"Contract {name} does not exist in storage").GetContract(existing.UnlockAccount.Eth. if (existing == null) throw new Exception($"Contract {name} does not exist in storage").ContractAddress).ContractAddress.UnlockAccount. if (!String. if (existing.and Load -ContractFromTableStorage because those are just simple Azure table interactions.Transactions. return existing. I’m going to skip over the Save. else { var resultUnlocking = await _web3.Abi.ContractAddress.GetContractFromTableStorage(name).Eth.SendRequestAsync(_accountAddress. 60). .SendRequestAsync(existing. Please call TryGetContractAddress until it returns the address"). var resultUnlocking = await _web3.Personal.SendRequestAsync(_accountAddress.GetTransactionReceipt.ContractAddress)) return existing.IsNullOrEmpty(existing. existing.GetContractFromTableStorage(name). we connect to port 8545 so it can do RPC json communication. if (receipt != null) { existing. } return null. } public async Task<Contract> GetContract(string name) { var existing = await this.ContractAddress == null) throw new Exception($"Contract address for {name} is empty. In the constructor we see the connection to our Geth process.ContractAddress. } } } return null. if (resultUnlocking) { var receipt = await _web3. } public async Task<string> TryGetContractAddress(string name) { // check contractName var existing = await this. } } } That is a lot of code.Personal. if (resultUnlocking) { return _web3.Tran sactionHash).ContractAddress = receipt. _password. _password. 60). await SaveContractToTableStorage(existing). Think of mining as the process that the peers of your blockchain do. contract CoinsContract { uint public balance. we can persist it. When 12 peers have done so. After that we can call the deploy method and get the transaction hash back. function CoinsContract(uint initial) { balance = initial.io/ . because our balance should be 2 coins when the contract is released.4.. So why you want to do that. The last method of our service is the GetContract and this just getting a reference to the Ethereum contract. return b. First let’s view our test solidity contract. If the GetTransactionReceipt returns a valid address. } function subtractCoins(uint add) returns (uint b) { b = balance . so that the contract gets accepted into the blockchain. this is nice to check the ether balance of an address like your account.FromWEi Second method implementation is ReleaseContract. Then we can call the add and subtract to modify our coin balance. This mining process cost money (aka Gas money) and will be deducted from the _accountAddress you have put in. } } It’s just a piggybank which based on its constructor value starts with that balance.6. We need this address to call the methods on it.add. If not we can start unlocking the account for 120 seconds.First method is. In our case we specify 2. This is needed because now the contract will be mined. We’ll be covering calling contracts after the next part. GetBalance. right? When the contract is released we can call addCoints or subtractCoints method from our dotNet code. it will only cost us ether? Well the upside is that every call to a method will be added to the distributive ledger and so can be viewed at https://testnet. Each contract has a different gas price. wallet or even a contract. Unlocking is needed when we want to deploy a contract or something else. As explained the deploy must be mined to get the contract address. this is like the cent to a euro but then 10^18 factor instead of 10^2. pragma solidity ^0. In our TryGetContractAddress we check if our contract has got an address already in our table storage and if not we ask the Ethereum Blockchain. I know this is very basic but that’s always nice for a start. This amount is in Wei and we specify this in our controller which will call the EthereumService. } function addCoins(uint add) returns (uint b) { b = balance + add. return b. We can specify the contract constructor parameter in the method SendRequestAsync. After we got our balance back in Wei. Since everything revolves around money. the contract address is given back. All Ethereum interaction is done through the object web3 in this example. It first checks if we didn’t already released the contract and persist it in storage. So now we do a step back from dotNet and go to the solidity program language. We can convert it back to Ether with the convert. This value is available when compiling the contract. As you can see the contract must exist in the table storage in order to get the contract address.etherscan. Controllers { [Route("api/[controller]")] public class EthereumTestController : Controller { private IEthereumService service. using EthereumStart. "ehtereumPassword": "y". } } } Second we add these settings to the appsettings.Configure<EthereumSettings>(Configuration).Mvc. Third we add to our startup.""type"":""uint256""}] . First. using System. "storageAccount": "v" Of course. set. For our last step. The ABI stands Application Binary Interface and is like the WSDL of a webservice. Once compiled we can get the Byte code (please don’t forget the 0x in front of it) and the Interface which is also called ABI.json.io/browser-solidity/ This rudimentary web-based editor you can compile and test your contract.Services. not with these values but with your own Ethereum account and password and with your Azure storage account and key. we create the settings file called EthereumSettings namespace EthereumStart. services.Model { public class EthereumSettings { public EthereumSettings() { } public string EhtereumAccount { get.github. set. set. } public string StorageAccount { get. We use the Remix website https://ethereum. "ehtereumAccount": "x". we need to compile it to byte code. "storageKey": "w". we add a controller with the name EthereumTestController and the contents should be.cs the code below in the ConfigureServices method. private const string abi = @"[{""constant"":false. set.AspNetCore. using Microsoft. BasicEthereumService>(). } public string EhtereumPassword { get. namespace EthereumStart. } public string StorageKey { get. Back to Visual Studio and we only have to do four more steps before we can release the contracts and start calling the methods. using System.""inputs"":[{""name"":""add"".AddScoped<IEthereumService. Both parts need to be supplied when releasing a contract.In order to release this contract.Threading. services.Tasks. ""inputs"":[{" "name"":""add"".""type"":""function""}.GetFunction(contractMethod)..""outputs "":[{""name"":""b"".""payable"": false.{""constant"":true.""outputs"":[{""name"":""b"".""name"":""addCoins"". try { .{""inputs"":[{""name"":""initial"".""type"":""uint256""}]. [FromRoute] int value) { string contractAddress = await service.""payable"":false.GetBalance(walletAddress).""name"":""balance"". } [HttpGet] [Route("releaseContract/{name}")] public async Task<bool> ReleaseContract([FromRoute] string name) { return await service. gas). if (contract == null) throw new System.""type"":""constructor""}]". private const string byteCode = "0x6060604052341561000c57fe5b6040516020806101858339810160405280805190602001 90919050505b806000819055505b505b610143806100426000396000f300606060405260003 57c0100000000000000000000000000000000000000000000000000000000900463ffffffff 1680630173e3f41461005157806349fb396614610085578063b69ef8a8146100b9575bfe5b3 41561005957fe5b61006f60048080359060200190919050506100df565b6040518082815260 200191505060405180910390f35b341561008d57fe5b6100a36004808035906020019091905 0506100f8565b6040518082815260200191505060405180910390f35b34156100c157fe5b61 00c9610111565b6040518082815260200191505060405180910390f35b60008160005401905 0806000819055508090505b919050565b600081600054039050806000819055508090505b91 9050565b600054815600a165627a7a723058200085d6d7778b3c30ba2e3bf4af4c4811451f7 367109c1a9b44916d876cb67c5c0029". } [HttpGet] [Route("getBalance/{walletAddress}")] public async Task<decimal> GetBalance([FromRoute]string walletAddress) { return await service.Exception("Contact not present in storage").{""constant"":false.""outputs"": [{""name"":"""". } [HttpGet] [Route("exeContract/{name}/{contractMethod}/{value}")] public async Task<string> ExecuteContract([FromRoute] string name.""name"":""subtractCoins"".ReleaseContract(name. byteCode.TryGetContractAddress(name). ""payable"":false.""type"":""uint256""}]. var contract = await service. [FromRoute] string contractMethod. private const int gas = 4700000.""inputs"":[]. var method = contract.GetContract(name).""type"":""uint256""}].""type"":""functio n""}.""type"":""uint256""}].""payable"":false.TryGetContractAddress(name) != null. public EthereumTestController(IEthereumService ethereumService) { service = ethereumService.""type"":""fun ction""}. } [HttpGet] [Route("checkContract/{name}")] public async Task<bool> CheckContract([FromRoute] string name) { return await service.""type"":""uint256""}]. abi. Then we have the 4 http calls we can invoke (please prepend your localhost + port yourself) /api /EthereumTest /getBalance /0xfC1857DD580B41c03D7 e086dD23e7cB e1f0Edd17 This checks a wallet and should return 5 Ehter /api /EthereumTest /releaseContract /coins This releases the contract saves the result to Azure storage.GetContract(name).ToString().SendTransactionAsync(service. We can see our contract calls on the Etherscan website as well. With this you can proof you did a transaction.GetFunction(functionName).CallAsync<int>().TryGetContractAddress(name).AccountAddress. var function = contract. Because it’s a transaction. [FromRoute] string functionName) { string contractAddress = await service. } } } It looks a lot of code but it’s a few methods. var contract = await service. } catch (Exception ex) { return "error". If true the contract address is present and we can invoke it. This maybe take some time (sometimes 2 minutes but sometimes 20 seconds) /api /EthereumTest /exeContract /coins /addCoins /123 The actual invoking of the contract and the method addCoins with value 123. value). var result = await method.CallAsync<int>(value). Here is one of ours /api /EthereumTest /checkValue /coins /balance When the transaction from our ExeContract is mined (validated) as well we can view our . /api /EthereumTest /checkContract /coins This checks if the contract address is available. second in the constructor we load the service. if (contract == null) throw new System. return result. Once this is called a transaction result is given. Etherscan is showing all transaction for the main and test network of Ethereum. It’s possible to use CallAsync but then it would be called in your local Ethereum VM. the transaction address is returned.Exception("Contact not present in storage"). First of all we have the ABI and Byte code of our contract. } } [HttpGet] [Route("checkValue/{name}/{functionName}")] public async Task<int> CheckValue([FromRoute] string name. var result = await function. // var result = await method. so this would not result in a transaction. return result. /api /EthereumTest /exeContract /coins /subtractCoins /5 Now we subtract 5 coins . After calling the contract with 123. The contract featured a public variable lastResult. check the balance again and it should be 120. .multiplication result. the balance would be 125. This can be called to get the current state.
Copyright © 2024 DOKUMEN.SITE Inc.