Block Cypher APIs Test Program

Prepared by: Ash Khan

In this tutorial, you’ll create a simple Web Interface to demonstrate how to create Block Chain Transactions using Block Cypher API. You will create User Wallets and Activity Wallets. You will perform Transactions where you transfer points from Activity Wallet to User wallet.

Before you start, make sure that you have the followed the getting started steps for Installing ASP.NET 5 On Windows. This tutorial assumes you have already installed Visual Studio 2015 and the latest ASP.NET 5 runtime and tooling.

Note

For additional information about installing ASP.NET 5 on other platforms, see Getting Started.

Introduction

The Block Chain provides Bitcoin’s public ledger, an ordered and timestamped record of transactions. This system is used to protect against double spending and modification of previous transaction records.

Create a new ASP.NET 5 project

Start Visual Studio 2015. From the File menu, select New > Project.

Select the ASP.NET Web Application project template. It appears under Installed > Templates > Visual C# > Web. Name the project BCWallet and click OK.

Create New Project

In the New ASP.NET Project dialog, select Web Application under ASP.NET 5 Preview Templates. Also, make sure the Host in the cloud checkbox is not selected and click OK.

/images/03-web-site-template.png

Note

Do not change the authentication method. Leave it as the default Individual User Accounts for this tutorial.

Review the project

In Visual Studio, the Solution Explorer window lets you manage files for the project. The web application template that you used to create this web app adds the following basic folder structure:

solution-explorer

Visual Studio creates some initial folders and files for your project. The primary files that you should be familiar with include the following:

File name Purpose
project.json The presence of a project.json file defines a .NET Execution Environment (DNX) project. It is the project.json file that contains all the information that DNX needs to run and package your project. For additional details, including the project.json file schema, see Working with DNX Projects.
global.json Visual Studio uses this file to configure the project.
appsettings.json This file allows you to include additional project information, such as connection string values. For more information, see Configuration.
Startup.cs The Startup class provides the entry point for an application. The Startup class must define a Configure method, and may optionally also define a ConfigureServices method, which will be called when the application is started. For more information, see Application Startup.
Index.cshtml This view contains the HTML for the default page of the view.
_Layout.cshtml This view contains common HTML for multiple pages of the web app.
HomeController.cs This controller contains the classes that handle incoming browser requests, retrieve model data, and then specify view templates that return a response to the browser.

In addition to these files the project is also setup to handle authenticating users. To learn more about authentication and identity in ASP.NET 5 see Authentication. For a more complete overview of the structure of an ASP.NET 5 project see Understanding ASP.NET 5 Web Apps. In this tutorial we will focus on adding functionality to our app using MVC and EF.

Understanding MVC

This project uses MVC. MVC stands for Model-View-Controller. MVC is a pattern for developing applications that are well architected, testable, and easy to maintain. MVC-based applications contain:

  • Models: Classes that represent the data of the application and that use validation logic to enforce business rules for that data.
  • Views: Template files that your application uses to dynamically generate HTML responses.
  • Controllers: Classes that handle incoming browser requests, retrieve model data, and then specify view templates that return a response to the browser.

Understanding .NET Core

.NET Core 5 is a modular runtime and library implementation that includes a subset of the .NET Framework. .NET Core 5 has been designed for Windows, Linux and OS X. It consists of a set of libraries, called “CoreFX”, and a small, optimized runtime, called “CoreCLR”. .NET Core is open-source, so you can follow progress on the project and contribute to it on GitHub. For more information, see Choosing the Right .NET For You on the Server.

Entity Framework

Entity Framework (EF) is an object-relational mapping (ORM) framework. It lets you work with relational data as objects, eliminating most of the data-access code that you’d usually need to write. Using EF, you can issue queries using LINQ, then retrieve and manipulate data as strongly typed objects. LINQ provides patterns for querying and updating data. Using EF allows you to focus on creating the rest of your application, rather than focusing on the data access fundamentals.

Open the project.json file. In the dependencies section, you will see the following lines related to EF:

  "dependencies": {
    "EntityFramework.Commands": "7.0.0-rc1-final",
    "EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",

These lines show that you can issue EF commands from the command window and that the EF NuGet package is included with your project.

Create a data model and scaffolding

Entity Framework supports a development paradigm called Code First. Code First lets you define your data models using classes. A class is a construct that enables you to create your own custom types by grouping together variables of other types, methods and events. You can map classes to an existing database or use them to generate a database. In this tutorial, you’ll begin by creating the entity classes that define the data models for the Web application. Then you will create a context class that manages the entity classes and provides data access to the database. You will then configure EF and populate the database.

Create entity classes

The classes you create to define the schema of the data are called entity classes. If you’re new to database design, think of the entity classes as table definitions of a database. Each property in the class specifies a column in the table of the database. These classes provide a lightweight, object-relational interface between object-oriented code and the relational table structure of the database.

The Web app will have two new entities:

  • Wallet
  • BlockChainAddr

You will define a class for each in the Models folder within Solution Explorer. Each class will define the

Note

You can put model classes anywhere in your project. The Models folder is just a convention.

Right-click the Models folder and select Add > New Item. In the Add New Item dialog, select the Class template. In the Name edit box, type “Business.cs” and click OK.

Business Class

Replace the default code with the following code:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace BCWallet.Models
{
                                            public class Wallet
                                            {
                                            [Key]
                                            public int ID { get; set; }
                                            public string Type { get; set; }
                                            public string Name { get; set; }
                                            public string Token { get; set; }
                                            public int AddrID { get; set; }
                                            }
                                            }
                                            public class BlockChainAddr
                                            {
                                            [Key]
                                            public int ID { get; set; }
                                            public string Address { get; set; }
                                            public string Private { get; set; }
                                            public string Public { get; set; }
                                            }
                                            }
                                            

Replace Index.cshtml

Replace the index.cshtmlScaffolding saves you time and coding effort by automatically generating the starting point for your application’s CRUD (Create, Read, Update and Delete) operations. Starting from a simple model class, and, without writing a single line of code, you will create two controllers that will contain the CRUD operations related to books and authors, as well as the all the necessary views.

To add a scaffolding, right-click the Controllers folder in Solution Explorer. Select Add –> New Scaffolded Item.

Add sample data

Rather than entering several sample records by hand, you will add code that will by used to populate your database. Add a class named SampleData in the Models folder with the following code:

                                            

@using DCoins.Models @model DemoViewModel @{ ViewBag.Title = "Demo"; ViewBag.ID = 1; ViewBag.Title = "Welcome To Deloitte"; ViewBag.AttendeeWalletAddress = Model.AtdAddr.Address; ViewBag.AttendeeWalletPrivate = Model.AtdAddr.Public; ViewBag.AttendeeWalletPublic = Model.AtdAddr.Private; ViewBag.VendorWalletAddress = Model.VndAddr.Address; ViewBag.VendorWalletPrivate = Model.VndAddr.Private; ViewBag.VendorWalletPublic = Model.VndAddr.Public; ViewBag.ActivityWalletAddress = Model.ActAddr.Address; ViewBag.ActivityWalletPrivate = Model.ActAddr.Private; ViewBag.ActivityWalletPublic = Model.ActAddr.Public; Layout = "~/Views/Shared/_DemoLayout.cshtml"; }

<h2 class="text-center">Loyalty and Rewards</h2> <div class="log"> Reward Points that Pay </div> <div class="btn-group-xs text-center"> <p> <button class="CreateWallet btn btn-primary btn-xs" id="Atd_1_Wallet">Create Wallet Attendee</button> <button class="CreateWallet btn btn-primary btn-xs" id="Act_1_Wallet">Create Wallet Activity</button> <button class="CreateWallet btn btn-primary btn-xs" id="Vnd_1_Wallet">Create Wallet Vendor</button> <button class="DeleteAllWallet btn btn-primary btn-xs" id="Del">Delete All Wallet</button> <button class="ListAllWallet btn btn-primary btn-xs" id="Lst">List All Wallet</button> </p> </div> <div class="btn-group-xs text-center"> <p> <button class="SeedMoney btn btn-primary btn-xs" id="Seed">Seed Money (100000)</button> <button class="Transaction btn btn-primary btn-xs" id="TouchPoints">Touch Points (1000)</button> <button class="Transaction btn btn-primary btn-xs" id="VendorDeposit"disabled>Vendor Deposit Back(10000)</button> <button class="Transaction btn btn-primary btn-xs" id="GoShopping"disabled>Go Shopping(15000)</button> <button class="Ledger btn btn-primary btn-xs" id="Act_1_Wallet">Activity Ledger</button> <button class="Ledger btn btn-primary btn-xs" id="Atd_1_Wallet">Attendee Ledger</button> <button class="Ledger btn btn-primary btn-xs" id="Vnd_1_Wallet">Vendor Ledger</button> </p> <div id="YesNo"></div> </div>

<div class="row"> <div class="col-md-12 panel panel-info"> <div class="panel-heading" id="PanelHeading">Ledger</div> <div class="panel-body" id="PanelBody"> <table class="transactionTable"> <thead> <tr> <th>#</th> <th>Amount</th> </tr> </thead> <tbody></tbody> </table> </div> </div> </div>

@section Scripts { <link rel="stylesheet" href="http://cdn.datatables.net/1.10.2/css/jquery.dataTables.min.css" /> <link rel="stylesheet" href="http//ajax.googleapis.com/ajax/libs/jqueryui/1/themes/base/jquery-ui.css" /> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/i18n/jquery-ui-i18n.min.js"> </script> <script type="text/javascript" src="http://cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js"> </script> <script> var token = "a69f77fb67260c211b9f876901912f9e"; $('button.CreateWallet').click(function (e) { var wlt = this.id; $.ajax({ type: "POST", url: 'https://api.blockcypher.com/v1/bcy/test/addrs?token=' + token, data: null, success: function (d) { var dest = d; $.ajax({ type: "POST", url: 'https://api.blockcypher.com/v1/bcy/test/wallets?token=' + token, data: JSON.stringify({ "name": wlt, "addresses": [dest.address] }), success: function (d) { $.ajax({ type: "POST", url: '/Home/DemoAddWallet', data: { "WalletName": wlt, "WalletToken": token, "Address": dest.address, "Public": dest.public, "Private": dest.private }, success: function (d) { alert("Wallet: " + wlt + " has been added"); location.reload(); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }) }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }) }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); })

$('button.DeleteAllWallet').click(function (e) { $.ajax({ type: "GET", url: 'https://api.blockcypher.com/v1/bcy/test/wallets?token=' + token, data: null, success: function (d) { $.each(d, function (index, data) { $.each(data, function (i, item) { if (item != "") { alert("Deleting Wallet: " + item); var data = 'https://api.blockcypher.com/v1/bcy/test/wallets/' + item + '?token=' + token; $.ajax({ url: data, method: "DELETE", success: function (d) { alert("Wallet: " + item + " Deleted"); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }) } }) }) }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); })

$('button.ListAllWallet').click(function (e) { $.ajax({ type: "GET", url: 'https://api.blockcypher.com/v1/bcy/test/wallets?token=' + token, data: {}, success: function (d) { alert(JSON.stringify(d)); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }) }) $('button.Ledger').click(function (e) { var wlt = this.id; $.ajax({ type: "GET", url: '/Home/DemoGetAddresses/?wallet=' + wlt, data: {}, success: function (d) { var Addresses = d.data; var ColumnAdded = false; var ColumnHeader = ""; var TableRows = ""; $.each(Addresses, function (index, Addr) { $.ajax({ type: "GET", url: 'https://api.blockcypher.com/v1/bcy/test/addrs/' + Addr + '/balance', data: {}, success: function (d) { if (!ColumnAdded) { var columnWidth = ""; var columns = ""; $.each(d, function (index, data) { columns = columns + '<th>' + index + '</th>' columnWidth = columnWidth + '<col width="130">'; }) ColumnHeader = columnWidth + "<tr>" + columns + "</tr>" ColumnAdded = true; } var row = ""; $.each(d, function (index, data) { row = row + '<td>' + data + '</td>' }) TableRows = TableRows + "<tr>" + row + "</tr>" }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); }) alert("TABLE: COL ROWS" + ColumnHeader + TableRows); $("table.transactionTable").empty().append(ColumnHeader + TableRows); $("#PanelHeading").text("Ledger: " + wlt); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); })

$('button.SeedMoney').click(function (e) { $.ajax({ type: "GET", url: '/Home/DemoGetAddresses/?wallet=Act_1_Wallet', data: {}, success: function (d) { var Addresses = d.data; $.each(Addresses, function (index, Addr) { var req = JSON.stringify({ "address": Addr, "amount": 100000 }); alert(req); $.ajax({ type: "POST", url: 'https://api.blockcypher.com/v1/bcy/test/faucet?token=' + token, data: req, success: function (d) { $("div.log").empty().append("<div>100,000 Points of Seed Money is being placed in the Activity Wallet</div>"); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); return; }) }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); })

$('#TouchPoints').click(function (e) { var Signatures = []; var UnsignedTX = null; var sourceAdd = null; //d.data[0]; var sourcePublic = null; var dest = null; //d.data[0]; //function pinger(ws) { // var timer = setInterval(function () { // if (ws.readyState == 1) { // ws.send(JSON.stringify({ event: "ping" })); // } // }, 5000); // return { stop: function () { clearInterval(timer); } }; //} //function waitForConfirmation(finaltx) { // if (checkError(finaltx)) return; // jsonlog("Transaction " + finaltx.tx.hash + " to " + dest.address + " of " + // finaltx.tx.outputs[0].value / 100000000 + " BTC sent."); // var ws = new WebSocket("wss://socket.blockcypher.com/v1/bcy/test"); // // We keep pinging on a timer to keep the websocket alive // var ping = pinger(ws); // ws.onmessage = function (event) { // if (JSON.parse(event.data).confirmations > 0) { // jsonlog("Transaction confirmed."); // ping.stop(); // ws.close(); // } // } // ws.onopen = function (event) { // ws.send(JSON.stringify({ filter: "event=new-block-tx&hash=" + finaltx.tx.hash })); // } // log("Waiting for confirmation... (may take > 10 min)") //} function checkError(msg) { if (msg.errors && msg.errors.length) { $("div.log").empty().append("<div>" + "Errors occured!!/n" + msg.errors.join("/n") + "</div>"); return true; } }

function signAndSend(newtx) { alert(" SIGN" + JSON.stringify(newtx)); if (checkError(newtx)) return; $.ajax({ type: "POST", url: 'https://api.blockcypher.com/v1/bcy/test/txs/send', data: JSON.stringify(newtx), success: function (d) { alert("SIGN AND SEND" + JSON.stringify(d)); $.ajax({ type: "POST", url: '/Home/DemoAddWallet', data: { "WalletName": "Atd_1_Wallet", "WalletToken": token, "Address": dest.address, "Public": dest.public, "Private": dest.private }, success: function (d) { $("div.log").empty().append("<div>1000 Points have been added to your Wallet</div>"); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }) }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert("ERR: " + JSON.stringify(XMLHttpRequest)); $("div.log").append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); }

function postUnsignedTx(d) { var postData = { "tosign": d, "sourceWalletName": "Act_1_Wallet" } $.post("/Home/UnsignedTX", postData).done(function (data) { Signatures = data.Message; UnsignedTX.pubkeys = []; UnsignedTX.signatures = []; $.each(Signatures, function (index, value) { UnsignedTX.pubkeys.push(sourcePublic); UnsignedTX.signatures.push(value); }); signAndSend(UnsignedTX); }); } $.ajax({ type: "POST", url: 'https://api.blockcypher.com/v1/bcy/test/wallets/Atd_1_Wallet/addresses/generate?token=' + token, data: {}, success: function (d) { dest = d; $.ajax({ type: "GET", url: '/Home/DemoGetPublicAddresses/?wallet=Act_1_Wallet', data: {}, success: function (d) { sourceAddr = d.data[0]; sourcePublic = d.data[1]; var newtx = { "inputs": [{ "addresses": [sourceAddr] }], "outputs": [{ "addresses": [dest.address], "value": 1000 }] } alert(JSON.stringify(newtx)); $.ajax({ type: "POST", url: 'https://api.blockcypher.com/v1/bcy/test/txs/new', // + '?token=' + token, data: JSON.stringify(newtx), success: function (d) { UnsignedTX = d; var tx_tosign = d.tosign; postUnsignedTx(tx_tosign); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); }, error: function (XMLHttpRequest, textStatus, errorThrown) { $("div.log").empty().append("<div>" + JSON.stringify(XMLHttpRequest) + "</div>"); } }); }) </script> }

Notice in ConfigureServices the app calls Configuration["Data:DefaultConnection:ConnectionString"] to get the database connection string. During development, this setting comes from the appsettings.json file. When you deploy the app to a production environment, you set the connection string in an environment variable on the host. If the Configuration API finds an environment variable with the same key, it returns the environment variable instead of the value that is in appsettings.json.

Build the web application

To make sure that all the classes and changes to your Web application work, you should build the application.

From the Build menu, select Build Solution.

The Output window is displayed, and if all went well, you see a succeeded message.

/images/19-vs-build-output.png

If you run into an error, re-check the above steps. The information in the Output window will indicate which file has a problem and where in the file a change is required. This information will enable you to determine what part of the above steps need to be reviewed and fixed in your project.

Note

Before running the app, you must first create the database using the data migrations.

Using data migrations to create the database

Data migrations in EF are used to perform model updates throughout your entire application. By initially using data migrations to create your database, you can modify your database after the model has changed with simple steps. This will allow you to build and maintain your web app more efficiently. The alternative to data migrations, where model or schema changes are required after the database has been created, involves recreating your entire database.

Open a Command Prompt in the project directory (BCWallet/src/BCWallet).

Note

To open the Command Prompt, you can right-click the Windows start button and select Command Prompt from the menu.

To find the project directory, in Visual Studio you can right-click the project name (BCWallet) in the Solution Explorer and select Open Folder in File Explorer. Copy your project path from File Explorer so you can copy it to the Command Prompt. For example, enter the following from the Command Prompt to change directories:

cd C:\Projects\BCWallet\src\BCWallet

Note

Make sure that you have navigated to the BCWallet folder within the src folder.

Run each of the following commands from the Command Prompt:

dnu restore
dnx ef migrations add Initial
dnx ef database update

Note

If dnu restore is not a recognized command, you may have missed a prerequisite step (or part of a prerequisites step) at the beginning of this topic. See Install the .NET Version Manager (DNVM) and Install the .NET Execution Environment (DNX).

Running dnu restore will restore the package dependencies specified in your project.json file. The ef command is specified in the project.json file of your project. For more information about dnvm, dnu, and dnx, see DNX Overview.

The add Initial command creates a migration named “Initial” that adds code to the project, allowing EF to update the database schema. The update command creates the actual database. After you run this command, the Migrations folder of your project will be updated as follows:

/images/16-migrations.png

Note

For general EF command help, enter the following in the command window: dnx ef -?.

Also, you will be able to view the newly created database within SQL Server Object Explorer.

/images/16a-database.png

Adding navigation

Update the navigation for the web app. From Solution Explorer, open the Views/Shared/_Layout.cshtml file. Find the following markup:

<li><a asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-controller="Home" asp-action="Contact">Contact</a></li>

Replace the above markup with the following markup:

<li><a asp-controller="Books" asp-action="Index">Books</a></li>
<li><a asp-controller="Authors" asp-action="Index">Authors</a></li>

The above changes will add a link to view Books and a link to view Authors. You created each of these views when you added scaffolding to the project.

Build the web application

To make sure that all the classes and changes to your Web app work, you should build the app again.

From the Build menu, select Build Solution.

Run the web app locally

Run the app now to see how you can view all of the products or just a set of products limited by category.

In the Solution Explorer, right-click the project name and select View -> View in Browser. As an alternative, you can press the F5 key.

The browser will open and show the web app. Click on the Books link at the top of the page.

/images/19a-running-app.png

Close the browser and click the “Stop Debugging” icon in the toolbar of Visual Studio to stop the app.

Running the default app

Once Visual Studio finishes creating the app, run the app by selecting Debug -> Start Debugging. As an alternative, you can press F5.

It may take time to initialize Visual Studio and the new app. Once it is complete, the browser will show the running app.

/images/05-browser-startup.png

After reviewing the running Web app, close the browser and click the “Stop Debugging” icon in the toolbar of Visual Studio to stop the app.

Publish the web app to Azure App Service

In Solution Explorer of Visual Studio, right-click on the project and select Publish.

/images/20-vs-publish.png

In the Publish Web window, click on Microsoft Azure Web Apps and log into your Azure subscription.

/images/21-vs-publishwebdb.png

Make sure you are signed in to Azure with your Microsoft account, then click New to create a new Web app in Azure.

/images/22-vs-selectexistingdb.png

Enter a unique site name, and select an app service plan, resource group, and region. Also, choose to create a database server, along with a database username and password. If you’ve created a database server in the past, use that. When you’re ready to continue, click Create.

/images/23-vs-createwebappdb.png

On the Connection tab of the Publish Web window, click Publish.

/images/24-vs-publishwebdb-target.png

You can view the publishing progress in either the Output window or the Azure App Service Activity window within Visual Studio.

/images/25-vs-webpubactivity.png

When publishing to Azure is complete, your web app will be displayed in a browser running on Azure.

/images/26-browserazure.png

For additional publishing information, see Publishing and Deployment.