Blockchain & Solidity Program Lab Manual
ISBN 9788119221646

Highlights

Notes

  

Prog. 24:: Case Study on Blockchain

What is a Blockchain?

I’ll use an analogy to explain how a blockchain works. Let’s look at a bank.

Suppose that Alice wants to send money to Bob with a wire transfer.

All of her money is stored inside a bank account, which has two primary purposes:

It keeps track of how much money she has.

It provides an online portal that allows her to perform the wire transfer to Bob.

Whenever Alice authorizes the wire transfer, her bank processes the transaction and transfers money from her account to Bob’s.

Behind the scenes, the bank has two primary technical features that make this possible.

A database - the bank maintains a database ledger of all Alice’s transactions to determine her account balance and transaction history.

A network - the bank uses a network to process wire transfers so that funds can be sent from her account to Bob’s. It also gives her an online portal that she can connect to in order to do this.

Blockchain presents an alternative to this model by eliminating the need for a bank altogether.

Instead of sending money to Bob via wire transfer, she can send him cryptocurrency directly with a blockchain.

Much like a bank, the blockchain gives her a place to safely store her funds and send money to Bob. It replaces the two primary technical features of a bank.

A database - It that keeps track of how much money Alice has.

A network - Alice can connect to a blockchain in order to send money. When she does, the blockchain processes her transaction, and moves the funds from her account to Bob’s.

Because it serves both of these roles, you can think of a blockchain as both a network

*and* a database at the same time. Let’s examine both of these concepts further.

A blockchain is a peer-to-peer network, meaning it is a system of nodes, or computers, that all talk to one another.

It is like a world-wide computer that fully replaces the bank.

It is responsible for processing transactions so that Alice can send money to Bob. She simply needs to connect to a node on the network to initiate her transaction, and the blockchain handles the rest behind the scenes (more on that in the next section).

Now let’s examine how blockchain functions like a database.

Each node on the network maintains a copy of the data on the blockchain. For example, they all know how much money Alice has in her account.

Instead of a bank storing all this data inside a central database, the blockchain stores it redundantly on each node in the network. This makes it virtually impossible to tamper with the data.

For example, Alice cannot manipulate her account balance, because all the other nodes know how much money she really has.

Blockchain Vs Cryptocurrency

It is important to note that blockchain and cryptocurrency are not the same thing.

Bitcoin is a cryptocurrency, but blockchain is the underlying technology behind Bitcoin. Blockchains can be used for other purposes besides cryptocurrency which I’ll demonstrate throughout this tutorial.

How Does A Blockchain Work Step-By-Step?

Let’s continue on with the example from the previous section. Suppose Alice wants to send some Bitcoin cryptocurrency to Bob.

In order to do this, Alice and Bob each need an account on the Bitcoin blockchain. Their accounts are much like their usernames: Alice must know Bob’s username, or account address, in order to send cryptocurrency to him.

Next, Alice needs a Bitcoin wallet in order to send the transaction. In this scenario, her wallet reflects that she owns 10 Bitcoin (wow!). This is called her “account balance”.

Being very generous, she decides to send 1 BTC (Bitcoin) to Bob through this 3-step process:

    1. She enters Bob’s account address as the recipient.

    2. She specifies that she wants to send 1 BTC to Bob.

    3. She signs the transaction in order to make it official.

In the last step, Alice signs the transaction with her private key. If her account address is like her username, then her private key is like her password. This is sensitive data stored inside her Bitcoin wallet, which she will not share with anyone else.

Alice’s private key allows her to create digital signatures that authorize her transactions on the blockchian, like sending 1 BTC to Bob.

At this point, Alice has done everything she needs to in order to complete the transaction. The rest of the process happens behind the scenes on the Bitcoin blockchain. Let’s see how that works.

After Alice’s transaction has been signed, it is sent to to the Bitcoin network.

A select group of nodes called “miners” process her transaction, and record it on the blockchain.

Bitcoin miners must solve a mathematical puzzle called a “proof-of-work” problem in order to record Alice’s transaction on the blockchain. Each miner competes with one another to guess a random encrypted number called a “nonce”.

The miner that guesses this number first submits their answer, or “proof of work”. This authorizes them to record the transaction to the blockchain and receive a Bitcoin reward for winning the mining competition.

Whenever they record it, they create a new transaction record on the blockchain. Groupings of transactions are called “blocks” which get “chained together” to make up the blockchain.

During the mining process, the network reaches “consensus”, meaning that each node verifies that they have the same valid data as everyone else. This mechanism is called the “consensus algorithm”. Effectively, each node says, “yes, I have a valid copy of Alice’s transaction”.

If they all agree, then the transaction is complete. The cryptocurrency is transferred from Alice’s account to Bob’s. When Bob checks his wallet, he’ll see that he now has 1 BTC!

Why Do We Need Blockchain?

Let’s continue on with our banking example. Here are some of the reasons Alice might choose to use the blockchain to store and send money:

Transaction Speed: Suppose Alice and Bob lived in different countries. An international wire transfer could take days to complete. Instead, Alice can send Bob Bitcoin in a matter of minutes.

Transaction Fees: Let’s say Bob is a merchant, and Alice wants to pay him money for a very expensive service, say $10,000. If Alice paid Bob with a credit card, Bob would incur a transaction fee around 2%, or $200. Because Bob is Alice’s friend, she pays him with Bitcoin to save him money. Now Bob incurs no transaction fees, and Alice only pays a few extra dollars to send money to Bob.

No 3rd Parties: Alice and Bob do not need to involve any 3rd parties in order to transact with one another.They do not need to sign any documents at a bank or wait for clearance in order to send and receive money.

Transparency: Instead of a bank storing all of her account data inside a central database, it is instead stored on the blockchain. She can verify all of her account balance and transactions on the secure network.

Security: Traditional databases and IT systems can be vulnerable to attack. It is virtually impossible to “hack” the Bitcoin blockchain to change Alice’s account balance or transaction history.

Anti-Fraud: Because blockchain transactions are publicly verifiable, they enable companies to build anti-fraud solutions that make it very hard to fake transactions or embezzle funds.

How To Become A Blockchain Developer

Up until now, we have discussed how to send money with the Bitcoin blockchain. Now I want to focus on how to build applications that run on the blockchain. Bitcoin is quite limited in this area, so we will instead look at a different blockchain called Ethereum.

In addition to sending cryptocurrency, Ethereum allows developers to create decentralized applications, or dApps, that run on the blockchain. Ethereum achieves this with smart contracts, which are programs that run on the blockchain. Let’s see how these apps work.

Normally when you use a web application, you use a web browser to load a web page that talks to a central web server over a network. All of the code for this app lives inside this central server, and all the data is housed inside a central database.

Anytime you transact with this application, you must interact directly with this central server. This presents a few problems. The application creators could change the application code on the server, or the database at any time because they have full control.

We can eliminate these problems by using the blockchain instead.

We can use our browser to load a web page that talks directly to the blockchain instead of a backend server and database. We can store all of the application code and data on a blockchain instead of this central server. This is a fully transparent and trustworthy way of knowing that the application code and data won’t change. Why?

All of the backend code for the application will be made up of smart contracts. These are immutable (a.k.a. “unchangeable”) building blocks of blockchain applications.

Once the code is put on the blockchain, no one can change it, and we know it will work the same way every time.

Smart contracts are written in a language called Solidity which looks a lot like JavaScript. They’re in charge of reading/writing data to the blockchain, and executing any business logic that we program. They work much like a microservice on the web. Also, they’re called smart contracts because they represent an unchangeable digital covenant, or agreement.

All of the data for the application will be stored as transaction records, inside of blocks on the blockchain. As we saw earlier, each node on the network maintains a copy of this data to ensure that it is secure and unchanged.

That’s how a blockchain application works from a high level. In the next section, we’ll get a closer look by building one together.

How To Build A Blockchain Application

Let’s get a much deeper understanding of how blockchain works by building a full- stack application step-by-step. Here is a preview of the app that we’ll build together:

This is a blockchain social network powered by smart contracts where you can get paid to post.

Other users can tip your status updates with cryptocurrency, so that you’re rewarded for creating great content.

It’s censorship resistant, so nobody can restrict the content that you post or see.

We’ll even curate the news feed so that the most tipped posts appear at the top, instead of relying upon “an algorithm” that nobody understands.

It also has a slick mobile-friendly user interface, where everyone gets a fancy icon automatically for their account.

We’ll accomplish these main objectives in the next sections:

We’ll set up a blockchain.

Next, we’ll develop smart contracts for the social network.

Finally, we’ll create a client side website so that anyone can use our app and post to the newsfeed.

Part 1: Project Setup

Now let’s set up our development environment to start coding. We’ll install all the dependencies we need to build the project.

Node.JS

The first dependency you’ll need is Node.js, which will give you Node Package Manager (NMP). We’ll use NPM to install other dependencies in this tutorial. You can check if you already have Node installed by executing this command from your terminal:

$ node -v

If you don’t have it installed yet, you can download it directly from the Node.js website.

Ganache Blockchain

The next dependency is a development blockchain, which can be used to mimic the behavior of a production blockchain. We’ll use Ganache as our development blockchain for this tutorial. We can use it to develop smart contracts, build applications, and run tests. Find the latest release for your operating system here.

Truffle Framework

The next dependency is the Truffle Framework, which gives us a suite of tools for developing blockchain applications. It will enable us to develop smart contracts, write tests against them, and deploy them to the blockchain.

Install Truffle from the command line with NPM like this (NOTE: you must use this exact version of Truffle to follow along with this guide):

$ npm install -g truffle@5.0.2

Metamask Ethereum Wallet

Now let’s install the Metamask Ethereum Wallet in order to turn our web browser into a blockchain browser. Your current web browser most likely doesn’t support this

natively, so we need the Metamask extension for Google Chrome in order to connect to the blockchain.

Visit this link to install Metamask, or simply search for it in the Google Chrome web store. Upon installation, ensure that you’ve enabled it in your list of Chrome extensions (it should be “checked”). When it’s active, you will see a fox icon in the top right hand corner of your browser.

Project Setup

Now that we have installed all the dependencies we need, let’s build our blockchain app!

Find where you installed Ganache, and open it. Once it’s loaded, you have a blockchain running on your computer!

You should see 10 accounts provided by Ganache, each pre-mined with 100 fake Ether (don’t get excited, this Ether isn’t worth real money).

Each account has a unique public and private key pair. You can see each account’s address on the main screen here. Remember, accounts are much like “usernames” on the blockchain, and they represent each user who can post to our social network.

Now let’s create a new project for all of our application code. Instead of doing this from scratch, I’m going to use a template that I created to help us get started quickly. You can clone this template from github like this:

$ git clone https://github.com/dappuniversity/starter_kit

social-network

Now you can enter into the newly created project folder just like this:

$ cd social-network

Hooray! The project is set up instantly. Let’s take a look around to see what we generated.

Open the project in your text editor of choice, and find the truffle-config.js file. This is where we will store all of the settings for our Truffle project.

I have already configured the project to connect to the Ganache development blockchain on 127.0.0.1 port 7545 (you can see that under the networks > development section).

Next, notice that I have specified new values for

the contracts_directory and contracts_build_directory.

I have changed this from the default Truffle project configuration so that we can access these files from our front end application in the src directory. These values are normally ./contracts/ and ./build/contracts/.

Here is a complete list of all the files inside our project:

migrations directory: this is where the migration files will live that allow us to put new smart contracts on the blockchain.

node_modules directory: this is where all of our dependencies get installed for the project.

public directory: this where we’ll store the images for the project.

src directory: this is the main folder for our client-side website, and our smart contract source code.

./src/components directory: this is where we will develop all of the React.js components that power our client side website.

./src/contracts directory: this is the folder where we will develop the source code for our smart contracts with Solidity (remember, we customized this directory in the previous step).

Next, let’s look at the package.json file.

This file contains all of the project dependencies we need to build the application. I have included all the dependencies we need inside this starter kit template.

Let’s go ahead and install these dependencies like this:

$ npm install

Now, let’s boot up our web server to ensure that everything worked properly:

$ npm run start

If you did everything correctly, your web browser should open automatically to a page that looks like this:

YAY! You’ve just set up the project. This is all of the template code that we will modify to create our app.

You can see that we got several nice freebies by installing this stater kit:

Bootstrap: the project already includes the Bootstrap UI framework. Our project will look really nice without having to write a bunch of custom CSS ourselves.

React.js: the project already has React.js configured to help us create a rich user interface without writing boilerplate JavaScript code ourselves. All the code you see on screen right now is contained inside the App.js component.

Now, let’s code the smart contract to power the backend of the social network app. It will be in charge of reading/writing to and from the blockchain. It will allow users to create new posts so that they can be shared in the newsfeed and tipped by other users.

Create a new file from your terminal like this:

$ touch ./src/contracts/SocialNetwork.sol

This is the file where we’ll write all the Solidity source code for the smart contract (just a reminder, this is inside a custom src directory, which is different from a default truffle project).

Let’s create a simple “systems check” to ensure that our project is set up properly, and that we can deploy this smart contract to the blockchain successfully. Start by entering this code into the SocialNetwork.sol file:

pragma solidity ^0.5.0;

contract SocialNetwork {

// State variable

string public name;

// Constructor function

constructor () public {

name = “Blockchain Demo”;

}

}

I’ll explain this code. The first line declares the Solidity programming language version that we’ll use, i.e., pragma solidity ^0.5.0;.

Next, we create the smart contract with the contract keyword, followed by the smart contract name Social Network. All of the source code for the smart contract will live inside the curly braces after that {...}.

Next, we define a state variable that will represent the name of our smart contract. This state variable’s value will get stored directly to the blockchain itself, unlike a local variable which will not.

We specify that this variable is a string. We must do this because Solidity is a statically typed language, meaning once we specify that this variable is a string, it cannot be a different data type later like a number.

Then we declare the state variable public with a modifier. This tells Solidity that we want to read this variable value from outside the smart contract. Because we have done this, Solidity will automatically create a name() function behind the scenes that will return this variable’s value (we won’t have to code it ourselves).

Finally, we create a constructor function with the constructor keyword. This is a special function that gets called only once whenever the smart contract is created, i.e., deployed to the blockchain.

Inside this function, we set the value of the name state variable to “Blockchain Demo”.

That’s it! Now that we’ve created the basic smart contract, let’s deploy it to the blockchain.

In order to do this, we must create a new migration file. Truffle uses these migrations to add new files to the blockchain. These are similar to migration files in other development frameworks where you make changes to a database, like adding new columns in tables.

We can create a new file inside the migrations directory like this:

$ touch migrations/2_deploy_contracts.js

Note: this file is numbered so that Truffle knows the order to run the migrations in. Inside this file, add the following code:

var SocialNetwork = artifacts.require(“./SocialNetwork.sol”); module.exports = function(deployer) {

deployer.deploy(SocialNetwork);

};

This code simply tells Truffle that we want to deploy the Social Network smart contract to the blockchain. Don’t worry if you don’t understand everything inside this file. It is essentially a copy-and-paste of the 1_initial_migrations.js file, except the smart contract names are changed.

Now let’s put this smart contract on the blockchain (i.e. Ganache) by running the migrations from the command line like this:

$ truffle migrate

Now let’s open the Truffle console to interact with the smart contract like this:

$ truffle console

Inside the console, we can write JavaScript code to interact with our development blockchain and smart contracts. Let’s fetch an instance of the deployed social network smart contract and store it to a variable like this:

contract = await SocialNetwork.deployed()

// => undefined

You’ll see that the console returns undefined here. That’s ok. We simply need to enter the variable name to return is value like this:

contract

Now you should see a JavaScript version of your smart contract inside the console. We can read the address like this:

contract.address

This is the unique address of the smart contract on the blockchain. Next, let’s read the name of the smart contract like this:

name = await contract.name()

// undefined 
name

// => ‘Blockchain Demo’

Again, you must call the name variable from the console to read its value.

Congratulations! You have just coded your first smart contract and deployed it to the Ethereum blockchain.

Part 2: Create Posts

Let’s continue building out the smart contract. As we write the Solidity code, we will simultaneously write tests for the smart contract with JavaScript inside a separate file with for a few reasons:

It will save us time. Any time we make changes to the smart contract, we can ensure that all of the code we wrote before still works. Imagine having to hand-check this in the console every time!

It is vital to ensure that our smart contracts work properly before putting them on the blockchain. Remember, all the smart contract code is immutable. Once it’s deployed to the blockchain, we cannot change it. Our tests will ensure that the code is bug free before deployment.

Let’s create a new directory for the test file like this:

$ mkdir test

Now, let’s create a new file for the test like this:

$ touch ./test/SocialNetwork.test.js

Inside this file, we can scaffold a test for the smart contract with the help of the Mocha testing framework and the Chai assertion library that comes bundled with the Truffle framework. Let’s start off with this basic code:

const SocialNetwork = artifacts.require(‘./SocialNetwork.sol’)

require(‘chai’)

.use(require(‘chai-as-promised’))

.should()

contract(‘SocialNetwork’, (accounts) => {

let socialNetwork

before(async () => {

socialNetwork = await SocialNetwork.deployed()

})

describe(‘deployment’, async () => {

it(‘deploys successfully’, async () => {

const address = await socialNetwork.address

assert.notEqual(address, 0x0)

assert.notEqual(address, ‘‘)

assert.notEqual(address, null)

assert.notEqual(address, undefined)

})

it(‘has a name’, async () => {

const name = await socialNetwork.name()

assert.equal(name, ‘Blockchain Demo’)

})

})

})

This basic test checks for 2 things:

The smart contract was successfully deployed, i.e., it has an address.

The name is correct, i.e., “Blockchain Demo”.

This code should look very similar to the operations we performed inside the console from the previous section. Check out the companion video for a more detailed explanation of this test.

Now let’s run the test suite like this:

$ truffle test

YES!!! They pass!

Now that the test suite is set up, let’s continue developing the smart contract. We’ll program a way for users to create new posts in the social network.

We’ll start by creating a new function like this:

function createPost(string memory _content) public {

// More code goes inside here...

}

We use the function keyword followed by the name createPost, and then specify that it accepts one argument _content for the post’s text.

Finally, we use the public modifier to ensure that we can call the function outside the smart contract, i.e., from our tests or the client side website.

Next, we need a way to model the post. We’ll use a Struct for this. Solidity allows us to define our own data structures with Structs. In our case, we’ll define a Post struct like this:

contract SocialNetwork {

// ...

struct Post {

uint id;

string content;

uint tipAmount;

address payable author;

}

// ...

}

This struct allows us store the post’s id, content, tip amount, and author. We declare the data type for each of these values in the code above.

Next, let’s create a way to store new posts on the blockchain. We’ll use a Solidity mapping to do this:

contract SocialNetwork {

// ...

mapping(uint => Post) public posts;

// ...

}

This mapping will uses key-value pairs to store posts, where the key is an id, and the value is a post struct. These mappings are a lot like associative arrays or hashes in other programming languages.

Whenever we add new posts to the mapping, they will be stored on the blockchain.

Because we used the public modifier we can also fetch posts by calling the posts() function, which Solidity will create behind the scenes.

Next, let’s create a counter cache to generate post ids like this: contract SocialNetwork {

// ...

uint public postCount = 0;

// ...

}

We will increment this value whenever new posts are created to generate post ids (we’ll see that in action momentarily).

Now let’s put it all together and create new posts inside of the function like this: function createPost(string memory _content) public {

// Increment the post count

postCount ++;

// Create the post

posts[postCount] = Post(postCount, _content, 0, msg.sender);

}

Let me explain this code:

First, we increment the post count to create a new post id. Initially, this value was 0. We change it to 1 with the ++ operator because this is the first post. Subsequent function calls will follow this pattern, i.e. 2, 3, 4, etc...

Next, we instantiate a new post struct with Post(), and pass in the id, content, tip amount, and author.

Finally, we add the new post to the post mapping by passing in the id postCount, and setting it equal to the new Post struct.

I will also note that we use msg.sender to determine the author’s account address. This is a special variable value provided by Solidity that tells us the user who called the function. We don’t have to pass this value in as a function argument. We get it magically with Solidity.

Now, let’s trigger an event whenever the post is created. Solidity allows us to create events that external consumers can subscribe to like this:

contract SocialNetwork {

// ...

event PostCreated(

uint id,

string content,

uint tipAmount,

address payable author

);

// ...

}

Now we can trigger this event inside the function like this:

function createPost(string memory _content) public {

// Increment the post count

postCount ++;

// Create the post

posts[postCount] = Post(postCount, _content, 0, msg.sender);

// Trigger event

emit PostCreated(postCount, _content, 0, msg.sender);

}

Lastly, let’s add a validation to ensure that users can’t post blank content. We’ll do that in the first line of our function like this:

function createPost(string memory _content) public {

// Require valid content

require(bytes(_content).length > 0);

// Increment the post count

postCount ++;

// Create the post

posts[postCount] = Post(postCount, _content, 0, msg.sender);

// Trigger event

emit PostCreated(postCount, _content, 0, msg.sender);

}

This uses Solidity’s require to ensure that the post has content before the rest of the code executes. If the expression inside require evaluates to true, the function will continue execution. If not, it will halt.

That’s it! That’s the complete code for creating new posts. At this point your smart contract code should look like this:

contract SocialNetwork {

string public name;

uint public postCount = 0;

mapping(uint => Post) public posts;

struct Post {

uint id;

string content;

uint tipAmount;

address payable author;

}

event PostCreated(

uint id,

string content,

uint tipAmount,

address payable author

);

constructor() public {

name = “Blockchain Demo”;

}

function createPost(string memory _content) public {

// Require valid content

require(bytes(_content).length > 0);

// Increment the post count

postCount ++;

// Create the post

posts[postCount] = Post(postCount, _content, 0, msg.sender);

// Trigger event

emit PostCreated(postCount, _content, 0, msg.sender);

}

}

Now, let’s add some test examples to ensure that this function works. Add this code to your test file:

describe(‘posts’, async () => {

let result, postCount

before(async () => {

result = await socialNetwork.createPost(‘This is my first post’, {from: author})

postCount = await socialNetwork.postCount()

})

it(‘creates posts’, async () => {

// SUCESS

assert.equal(postCount, 1)

const event = result.logs[0].args

assert.equal(event.id.toNumber(), postCount.toNumber(), ‘id is correct’)

assert.equal(event.content, ‘This is my first post’, ‘content is correct’)

assert.equal(event.tipAmount, ‘0’, ‘tip amount is correct’)

assert.equal(event.author, author, ‘author is correct’)

// FAILURE: Post must have content

await socialNetwork.createPost(‘‘, {from: author}).should.be.rejected;

})

})

})

// ...

Next, modify the top of your test suite to look like this: contract(‘SocialNetwork’, ([deployer, author, tipper]) => {

}

This test checks for all the behavior we just added:

It checks that the post count was incremented, and that is now equal to 1.

Then, it digs into the transaction logs to inspect the post value from the event that we triggered inside the function. We check that the post id, content, tip amount, and author are correct.

Finally, we check that the function rejects posts that don’t have any content.

Also, we modified the test suite to include 3 different users: deployer, author,

and tipper. We can do this instead of using the accounts variable that was injected by default.

Now let’s run the tests like this:

$ truffle test

YAY! They pass.

Part 3: Tip Posts

In this section, we’ll create a function that allows users to tip others post with cryptocurrency. Before we do that, let’s address a few things.

First, I want to explain the concept of “gas”.

Any time we store data on the Ethereum blockchain, we must pay a gas fee with Ether (Ethereum’s cryptocurrency). This is used to pay the miners who maintain the network.

Since we stored a new post on the blockchain, a small fee was debited from our account. You can see that your account balance has gone down in Ganache.

While storing data on the blockchain costs money, fetching does not. In summary, reads are free, but writes cost gas.

Next, we need to add a test to ensure that we can list out all of the posts from the social network. Inside your test file, use this code:

it(‘lists posts’, async () => {

const post = await socialNetwork.posts(postCount)

assert.equal(post.id.toNumber(), postCount.toNumber(), ‘id is correct’)

assert.equal(post.content, ‘This is my first post’, ‘content is correct’)

assert.equal(post.tipAmount, ‘0’, ‘tip amount is correct’)

assert.equal(post.author, author, ‘author is correct’)

})

Now let’s move on to creating a function that allows other users to tip posts with cryptocurrency:

function tipPost(uint _id) public payable {

// ...

}

This function accepts the post id as its only argument. Note, that we use a new modifier called payable. This allows us to send cryptocurrency whenever we call this function. This uses function metadata instead of passing in cryptocurrency as a function argument.

Let’s add the code to tip the author whenever this function is called: function tipPost(uint _id) public payable {

// Fetch the post

Post memory _post = posts[_id];

// Fetch the author

address payable _author = _post.author;

// Pay the author by sending them Ether

address(_author).transfer(msg.value);

// Increment the tip amount

_post.tipAmount = _post.tipAmount + msg.value;

// Update the post

posts[_id] = _post;

}

Let me explain how this works:

First, we fetch the post from the blockchain and store a new copy in memory.

Next, we store the post author to a variable.

Then, we send the cryptocurrency to the author with the transfer function. Solidity allows us to read the cryptocurrency value with the special msg.value variable.

Next, we increment the tip amount for the post.

Finally, we save the updated post values by adding it back to the mapping, and storing it on the blockchain.

Awesome! That’s the basic tipping functionality. Let’s do a few more things before we finish this function.

Let’s define an event that gets triggered any time a new tip is created like this:

event PostTipped(

uint id,

string content,

uint tipAmount,

address payable author

);

Now let’s trigger this event in the last line of the function like this:

function tipPost(uint _id) public payable {

// Fetch the post

Post memory _post = posts[_id];

// Fetch the author

address payable _author = _post.author;

// Pay the author by sending them Ether

address(_author).transfer(msg.value);

// Increment the tip amount

_post.tipAmount = _post.tipAmount + msg.value;

// Update the post

posts[_id] = _post;

// Trigger an event

emit PostTipped(postCount, _post.content, _post.tipAmount, _author);

}

Finally, let’s add a validation that the post exists in the first line of the fun