Hands-on writing an Ethereum smart contract

This article is excerpted from the book "Blockchain Development Guide", edited by Shentu Qingchun, and co-edited by Song Bo, Zhang Peng, Wang Xiaoming, Ji Zhoudong, and Zuo Chuanmin.
For blockchain related drafts, article error correction, and seeking reports, please email [email protected]

How to deploy and invoke smart contracts

RPC

The previous chapters covered how to write, deploy and interact with contracts. Now it's time to talk about the details of communicating with the Ethereum network and smart contracts.

An Ethereum node provides an RPC interface. This interface gives Ðapps (decentralized applications) access to the Ethereum blockchain and functions provided by nodes, such as compiling smart contract code, using a subset of the JSON-RPC 2.0 specification (not supporting alerts and named parameters) as Serialization protocol, available on HTTP and IPC (unix domain interface on linux/OSX, called pipe's on Windows).

convention

The RPC interface uses some conventions that are not part of the JSON-RPC 2.0 specification, these conventions are as follows:

  • Numbers are hexadecimal encoded. This decision was made because some languages ​​have few or no restrictions on running extremely large numbers. To prevent these errors the number type is hexadecimal encoded and it is up to the developer to parse the numbers and handle them correctly. See the Hexadecimal Encodings section on Wikipedia for examples.

  • Default block number. Several RPC methods accept block numbers. In some cases it is impossible or inconvenient to give the block number. In that case, the default block number can be one of the following strings ["earliest", "latest", "pending"]. See the wiki page for a list of RPC methods that use default block parameters.

deploy contract

We'll go through different steps to deploy the contract below, but only use the RPC interface.

contract Multiply7 {
event Print(uint);
function multiply(uint input) returns (uint) {
Print(input
*
7);
return input
*
7;
}
}

The first thing to do is to make sure the HTTP RPC interface is available. This means that we are starting to supply the --rpc flag for geth and the -j flag for eth. In this example, a geth node on a private development chain is used. With this approach, we don't need ether on the real network.

\> geth --rpc --dev --mine --minerthreads 1 --unlock 0 console 2>>geth.log

This starts the HTTP RPC interface on http://localhost:8545 .

Note: geth supports CORS see the --rpccorsdomain flag for more.
We can prove that the interface is working by retrieving the coinbase address and balance with curl. Note that the data in these examples will be different on your local node. If you want to experiment with these parameters, substitute the required parameters as appropriate.

\> curl --data '{"jsonrpc":"2.0","method":"eth_coinbase", "id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":["0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"]}
> curl --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"], "id":2}' localhost:8545
{"id":2,"jsonrpc":"2.0","result":"0x1639e49bba16280000"}

Remember when I said earlier that numbers are hexadecimal encoded? In this case, the balance is returned as Wei as a hexadecimal string. If you want the balance to be in digital ether, you can use web3 from the console, the example is as follows:

\> web3.fromWei("0x1639e49bba16280000", "ether")
"410"

Now that we have some ether on the private development chain, the contract can be deployed. The first step is to verify that the solidity compiler is available. The available compilers can be retrieved with the eth_getCompilers RPC method, for example:

\> curl --data '{"jsonrpc":"2.0","method": "eth_getCompilers", "id": 3}' localhost:8545
{"id":3,"jsonrpc":"2.0","result":["Solidity"]}

We can see that the solidity compiler is available.

The next step is to compile the Multiply7 contract into bytecode that can be sent to the Ethereum Virtual Machine, example:

\> curl --data '{"jsonrpc":"2.0","method": "eth_compileSolidity", "params": ["contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
{"id":4,"jsonrpc":"2.0","result":{"Multiply7":{"code":"0x6060604052605f8060106000396000f360606040

Now that we have compiled code, we need to decide how much gas it will take to deploy it. The RPC interface has the eth_estimateGas method, which will give us an estimated quantity, as follows:

\> curl --data '{"jsonrpc":"2.0","method": "eth_estimateGas", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "data": "0x6060604052605f8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b60586004356007810260609081526000907f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da90602090a15060070290565b5060206060f3"}], "id": 5}' localhost:8545
{"id":5,"jsonrpc":"2.0","result":"0xb8a9"}

Finally deploy the contract.

\> curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "gas": "0xb8a9", "data": "0x6060604052605f8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b60586004356007810260609081526000907f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da90602090a15060070290565b5060206060f3"}], "id": 6}' localhost:8545
{"id":6,"jsonrpc":"2.0","result":"0x3a90b5face52c4c5f30d507ccf51b0209ca628c6824d0532bcd6283df7c08

The transaction is accepted by the node, and the transaction hash table is returned. We can use this hash table to track transactions.

The next step is to decide where to deploy the contract. Each executed transaction creates a receipt. This receiver contains various information about the transaction, such as which block the transaction was included in, and how much gas the Ethereum Virtual Machine used. If the transaction creates a contract, it also contains the contract address. We can retrieve the receipt with the eth_getTransactionReceipt RPC method, for example:

\> curl --data '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": ["0x3a90b5face52c4c5f30d507ccf51b0209ca628c6824d0532bcd6283df7c08a7c"], "id": 7}' localhost:8545
{"id":7,"jsonrpc":"2.0","result":{"transactionHash":"0x3a90b5face52c4c5f30d507ccf51b0209ca628c682

As you can see, the contract was created at 0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d. If you get zero instead of receiving, it has not been included in the block. At this point, check to see if your miner is running and try again.

Interact with smart contracts

Now that the contract is deployed, we can interact with it. There are two ways to interact, sending a transaction or calling. In the example in this section, the transaction will be sent to the contract's multiply method.

In our case, the from, to, and data parameters need to be specified. From is the public address of our account, to is the contract address, and the Data parameter is a bit more complicated, it includes the payload that specifies which method to call and which parameter. That's where the ABI comes into play, which dictates how data is specified and encoded for the Ethereum Virtual Machine.

The bytes of the payload are function selectors that specify which method to call. It takes the first 4 bytes of the Keccak hash table, covering the function name parameter type, and encodes it in hexadecimal. The multiply function accepts one parameter. An example is as follows:

\> web3.sha3("multiply(uint256)").substring(0, 8)
"c6888fa1"

The next step is to encode the parameters. We only have one unit256, assuming the value 6 is provided. The ABI has a section that specifies how to encode uint bytes, as follows:

int<M>: enc(X) is the big-endian two’s complement encoding of X, padded on the higher-oder (left) side with 0xff for negative X and with zero 字节s for positive X such that the length is a multiple of 32 bytes.

It would encode to
00000000000000000000000000000000000000000000000000000000000006.
Combining the function selector with the encoding parameter, the data becomes 0xc6888fa10000000000000000000000000000000000000000000000000000000000006.

Let's try it out:

\> curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "to": "0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d", "data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}], "id": 8}' localhost:8545
{"id":8,"jsonrpc":"2.0","result":"0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869

Since we sent the transaction, there is a transaction table returned. If you retrieve the reception, you can see some new content, as follows:

{
blockHash: "0xbf0a347307b8c63dd8c1d3d7cbdc0b463e6e7c9bf0a35be40393588242f01d55",
blockNumber: 268,
contractAddress: null,
cumulativeGasUsed: 22631,
gasUsed: 22631,
logs: [{
address: "0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d",
blockHash: "0xbf0a347307b8c63dd8c1d3d7cbdc0b463e6e7c9bf0a35be40393588242f01d55",
blockNumber: 268,
data: "0x000000000000000000000000000000000000000000000000000000000000002a",
logIndex: 0,
topics: ["0x24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"],
transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74",
transactionIndex: 0
}],
transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74",
transactionIndex: 0
}

Receive contains a log. Logs are generated by the Ethereum Virtual Machine when transactions are executed, including receipts. If we look at the Multiply function, we can see that the print event is raised along with the input count of 7. Since the argument to the print event is uint256, it can be encoded according to the ABI rules, which will give you the expected decimal 42.

\> web3.sha3("Print(uint256)")
"24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"

This is just a brief introduction to some of the most common tasks. See the full list of available RPC methods on the RPC wiki page.

Web3.js

As seen in the previous case, using the JSON-RPC interface is rather tedious and error-prone, especially when dealing with ABIs. Web3.js is a Javascript library whose goal is to provide a more friendly interface and reduce the chance of errors.

Deploying a Multiply7 contract with web3 looks like this:

var source = 'contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
var compiled = web3.eth.compile.solidity(source);
var code = compiled.Multiply7.code;
var abi = compiled.Multiply7.info.abiDefinition;
web3.eth.contract(abi).new({from: "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", data: code}, function (err, contract) {
if (!err && contract.address)
console.log("deployed on:", contract.address);
}
);
deployed on: 0x0ab60714033847ad7f0677cc7514db48313976e2

Load a deployed contract and send the transaction:

var source = 'contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
var compiled = web3.eth.compile.solidity(source);
var Multiply7 = web3.eth.contract(compiled.Multiply7.info.abiDefinition);
var multi = Multiply7.at("0x0ab60714033847ad7f0677cc7514db48313976e2")
multi.multiply.sendTransaction(6, {from: "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"})

Register a callback that will be called when the event creation log is printed.

multi.Print(function(err, data) { console.log(JSON.stringify(data)) })
{"address":"0x0ab60714033847ad7f0677cc7514db48313976e2","args": {"":"21"},"blockHash":"0x259c7dc0

See more information on the web3.js wiki page.

console

geth console provides command line interface and Javascript execution time. It can connect to local or remote geth or eth nodes. It will load the web3.js library that users can use, so that users can deploy and interact with smart contracts through web3.js from the console. In fact the examples from the Web3.js chapter can be copied into the console and invoked.

View Contracts and Transactions

There are several online blockchain browsers available that allow you to query the Ethereum blockchain, they are:

  • EtherChain
  • EtherCamp
  • EtherScan

Other resources to view nodes or transactions

  • EtherNodes : Geographical distribution of nodes, differentiated by clients.
  • EtherListen: Real-time Ethereum transaction visualizer and listener.

Smart contract case in action

Ethereum is the best programming platform in the field of blockchain development, and truffle is one of the most popular development frameworks in Ethereum, which is why truffle is introduced. The actual combat is the most important thing. This article does not talk about the principle, but only builds the environment and runs the first blockchain program (Dapp).

1. Install truffle

The command to install truffle is as follows:

$ npm install -g truffle

2. Depends on the environment

Available systems include: Windows, Linux, and Mac OS X, Mac OS X is recommended, Windows is not recommended, and you will encounter various problems that may lead to abandonment. First, visit the official website of https://nodejs.org to download and install NodeJS.

Additionally, an Ethereum client needs to be installed to support JSON RPC API calls.

As for the development environment, EthereumJS TestRPC is recommended, the address is: https://github.com/ethereumjs/testrpc .

The installation command is as follows:

$ npm install -g ethereumjs-testrpc

3. Create the first project

Create a new project with the following command:

$ mkdir zhaoxi
$ cd zhaoxi
$ truffle init

By default, a MetaCoin demo will be generated, from which you can learn the architecture of truffle.

The directory structure of the project is shown in Figure 5-3.

write picture description here
Figure 5-3 Directory structure of the project

The directory of all files of the project is shown in Figure 5-4.

write picture description here
Figure 5-4 Project file directory directory structure

Now compile the project by the following command.

$ truffle compile

Figure 5-5 is the result after running the above command.

write picture description here
Figure 5-5 Truffle compile execution result

The following describes how to deploy the project.

Start TestRPC before deployment, the command is as follows:

$ testrpc 
$ truffle deploy(在Truffle 2.0以上版本中,命令变成了:truffle migrate)

Figure 5-6 is the result of running truffle deploy.

write picture description here
Figure 5-6 Truffle deploy execution result diagram

The execution result of $ truffle migrate migrate is shown in Figure 5-7.

write picture description here
Figure 5-7 Execution result of truffle migrate migrate

Now, the service can be started with the following command:

$ truffle serve

Figure 5-8 shows the execution result of truffle serve

write picture description here
Figure 5-8 Execution result of truffle serve

After starting the service, you can access the project in the browser, the address is: http://localhost:8080/ , the web interface is shown in Figure 5-9.

write picture description here
Figure 5-9 Smart contract running interface

Well, the first blockchain program is running, and you can continue to practice and learn in depth later.

write picture description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325386849&siteId=291194637